analyzer: rework AnalysisErrorListener deprecation

Work towards #60635

In this change, we rework the AnalysisErrorListener deprecation to
better support users who have their own class that implements
AnalysisErrorListener. This change introduces a sealed supertype,
DiagnosticOrErrorListener, with the old implementation,
AnalysisErrorListener, and the new implementation, DiagnosticListener,
as its sole direct subclasses. Users who have implemented
AnalysisErrorListener should be able to instead implement
DiagnosticListener, and their class is an acceptable instance of
DiagnosticOrErrorListener, wherever that is needed.

In a breaking change we can drop AnalysisErrorListener and deprecate
DiagnosticOrErrorListener, and in the next breaking change, we can drop
DiagnosticOrErrorListener.

For reference, see the first API difference when deprecating AnalysisErrorListener and introducing DiagnosticListener: https://github.com/dart-lang/sdk/commit/903d77cc8229972a424941dcb7b7b79741e833eb#diff-dec15868961d7eadcd009f49d129bebcdb747aaa8dbfde5f5a08884e0cf11e32

Change-Id: I3ccf11d54b41fbca98d020d89978d250c16b4c04
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/436480
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
Sam Rawlins
2025-06-25 06:54:20 -07:00
committed by Commit Queue
parent bf97e28b6d
commit ee69f45a1f
23 changed files with 119 additions and 63 deletions
@@ -678,7 +678,7 @@ class _MinimalEditComputer {
var scanner = Scanner(
_SourceMock.instance,
CharSequenceReader(s),
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
)..configureFeatures(
featureSetForOverriding: featureSet,
featureSet: featureSet,
@@ -115,7 +115,7 @@ class TransformSetManager {
try {
var content = file.readAsStringSync();
var parser = TransformSetParser(
DiagnosticReporter(DiagnosticListener.NULL_LISTENER, FileSource(file)),
DiagnosticReporter(DiagnosticListener.nullListener, FileSource(file)),
packageName,
);
return parser.parse(content);
@@ -26,7 +26,7 @@ List<Token> _getTokens(String text, FeatureSet featureSet) {
var scanner = Scanner(
_SourceMock.instance,
CharSequenceReader(text),
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
)..configureFeatures(
featureSetForOverriding: featureSet,
featureSet: featureSet,
@@ -226,7 +226,7 @@ class Driver {
var scanner = Scanner(
_TestSource(),
CharSequenceReader(text),
error.DiagnosticListener.NULL_LISTENER,
error.DiagnosticListener.nullListener,
)..configureFeatures(
featureSetForOverriding: featureSet,
featureSet: featureSet,
@@ -137,7 +137,7 @@ class GatheringDiagnosticListener implements DiagnosticListener {
/// Adds the given [diagnostics] to this listener.
void addAll(List<Diagnostic> diagnostics) {
for (var diagnostic in diagnostics) {
onError(diagnostic);
onDiagnostic(diagnostic);
}
}
@@ -388,7 +388,7 @@ class GatheringDiagnosticListener implements DiagnosticListener {
}
@override
void onError(Diagnostic diagnostic) {
void onDiagnostic(Diagnostic diagnostic) {
_diagnostics.add(diagnostic);
}
@@ -443,7 +443,7 @@ class TokenUtils {
var scanner = Scanner(
_SourceMock(),
CharSequenceReader(s),
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
)..configureFeatures(
featureSetForOverriding: featureSet,
featureSet: featureSet,
+6 -2
View File
@@ -17,8 +17,12 @@
* Deprecate `ErrorSeverity`; use `DiagnosticSeverity` instead.
* Deprecate `DiagnosticCode.errorSeverity`; use
`DiagnosticCode.diagnosticSeverity` instead.
* Deprecate `ErrorListener` and `RecordingErrorListener`; use
`DiagnosticListener` and `RecordingDiagnosticListener` instead.
* Deprecate `AnalysisErrorListener`, `BooleanErrorListener`, and
`RecordingErrorListener`; use `DiagnosticListener`,
`BooleanDiagnosticListener`, and `RecordingDiagnosticListener` respectively,
instead. Instead of calling or overriding `AnalysisErrorListener.onError`,
call or override `DiagnosticListener.onDiagnostic`. Instead of using
`AnalysisErrorListener.NULL_LISTENER`, use `DiagnosticListener.nullListener`.
* Deprecate `RecordingErrorListener.errors`; use
`RecordingDiagnosticListener.diagnostics` instead.
* Deprecate `RecordingErrorListener.getErrorsForSource`; no longer supported.
+15 -7
View File
@@ -4770,16 +4770,22 @@ package:analyzer/error/error.dart:
ErrorSeverity (type alias for DiagnosticSeverity, deprecated)
ErrorType (type alias for DiagnosticType, deprecated)
package:analyzer/error/listener.dart:
BooleanDiagnosticListener (class extends Object implements DiagnosticListener):
AnalysisErrorListener (class extends Object implements DiagnosticOrErrorListener, deprecated):
NULL_LISTENER (static getter: AnalysisErrorListener)
new (constructor: AnalysisErrorListener Function())
onError (method: void Function(Diagnostic))
BooleanDiagnosticListener (class extends Object implements AnalysisErrorListener, DiagnosticListener):
new (constructor: BooleanDiagnosticListener Function())
errorReported (getter: bool)
onDiagnostic (method: void Function(Diagnostic))
onError (method: void Function(Diagnostic))
DiagnosticListener (class extends Object):
NULL_LISTENER (static getter: DiagnosticListener)
DiagnosticListener (class extends Object implements DiagnosticOrErrorListener):
nullListener (static getter: DiagnosticListener)
new (constructor: DiagnosticListener Function())
onError (method: void Function(Diagnostic))
onDiagnostic (method: void Function(Diagnostic))
DiagnosticOrErrorListener (class extends Object, sealed (immediate subtypes: AnalysisErrorListener, DiagnosticListener))
DiagnosticReporter (class extends Object):
new (constructor: DiagnosticReporter Function(DiagnosticListener, Source))
new (constructor: DiagnosticReporter Function(DiagnosticOrErrorListener, Source))
lockLevel (getter: int)
lockLevel= (setter: int)
source (getter: Source)
@@ -4791,13 +4797,15 @@ package:analyzer/error/listener.dart:
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}))
reportError (method: void Function(Diagnostic))
RecordingDiagnosticListener (class extends Object implements DiagnosticListener):
RecordingDiagnosticListener (class extends Object implements AnalysisErrorListener, DiagnosticListener):
new (constructor: RecordingDiagnosticListener Function())
diagnostics (getter: List<Diagnostic>)
errors (getter: List<Diagnostic>, deprecated)
getErrorsForSource (method: List<Diagnostic> Function(Source), deprecated)
onDiagnostic (method: void Function(Diagnostic))
onError (method: void Function(Diagnostic))
AnalysisErrorListener (type alias for DiagnosticListener, deprecated)
DiagnosticOrErrorListenerExtension (extension on DiagnosticOrErrorListener):
onDiagnostic (method: void Function(Diagnostic))
BooleanErrorListener (type alias for BooleanDiagnosticListener, deprecated)
ErrorReporter (type alias for DiagnosticReporter, deprecated)
RecorderingErrorListener (type alias for RecordingDiagnosticListener, deprecated)
+65 -22
View File
@@ -16,9 +16,6 @@ import 'package:analyzer/src/utilities/extensions/collection.dart';
import 'package:meta/meta.dart';
import 'package:source_span/source_span.dart';
@Deprecated("Use 'DiagnosticListener' instead")
typedef AnalysisErrorListener = DiagnosticListener;
@Deprecated("Use 'BooleanDiagnosticListener' instead")
typedef BooleanErrorListener = BooleanDiagnosticListener;
@@ -28,9 +25,26 @@ typedef ErrorReporter = DiagnosticReporter;
@Deprecated("Use 'RecordingDiagnosticListener' instead")
typedef RecorderingErrorListener = RecordingDiagnosticListener;
/// An [DiagnosticListener] that keeps track of whether any diagnostic has been
/// An object that listens for [Diagnostic]s being produced by the analysis
/// engine.
@Deprecated("Use 'DiagnosticListener' instead")
abstract class AnalysisErrorListener implements DiagnosticOrErrorListener {
/// A diagnostic listener that ignores diagnostics that are reported to it.
@Deprecated("Use 'DiagnosticListener.nullListener' instead")
static const AnalysisErrorListener NULL_LISTENER = _NullErrorListener();
/// This method is invoked when a [diagnostic] has been found by the analysis
/// engine.
void onError(Diagnostic diagnostic);
}
/// A [DiagnosticListener] that keeps track of whether any diagnostic has been
/// reported to it.
class BooleanDiagnosticListener implements DiagnosticListener {
class BooleanDiagnosticListener
implements
// ignore: deprecated_member_use_from_same_package
AnalysisErrorListener,
DiagnosticListener {
/// A flag indicating whether a diagnostic has been reported to this listener.
bool _diagnosticReported = false;
@@ -38,28 +52,28 @@ class BooleanDiagnosticListener implements DiagnosticListener {
bool get errorReported => _diagnosticReported;
@override
void onError(Diagnostic diagnostic) {
void onDiagnostic(Diagnostic diagnostic) {
_diagnosticReported = true;
}
@override
void onError(Diagnostic diagnostic) => onDiagnostic(diagnostic);
}
/// An object that listens for [Diagnostic]s being produced by the analysis
/// engine.
abstract class DiagnosticListener {
abstract class DiagnosticListener implements DiagnosticOrErrorListener {
/// A diagnostic listener that ignores diagnostics that are reported to it.
static const DiagnosticListener NULL_LISTENER = _NullDiagnosticListener();
static const DiagnosticListener nullListener = _NullDiagnosticListener();
/// This method is invoked when a [diagnostic] has been found by the analysis
/// engine.
// TODO(srawlins): Rename to 'onDiagnostic'.
void onError(Diagnostic diagnostic);
void onDiagnostic(Diagnostic diagnostic);
}
sealed class DiagnosticOrErrorListener {}
/// An object used to create diagnostics and report them to a diagnostic
/// listener.
class DiagnosticReporter {
/// The diagnostic listener to which diagnostics are reported.
final DiagnosticListener _diagnosticListener;
final DiagnosticOrErrorListener _diagnosticListener;
/// The source to be used when reporting diagnostics.
final Source _source;
@@ -211,7 +225,7 @@ class DiagnosticReporter {
contextMessages ??= [];
contextMessages.addAll(convertTypeNames(arguments));
_diagnosticListener.onError(
_diagnosticListener.onDiagnostic(
Diagnostic.tmp(
source: _source,
offset: offset,
@@ -266,14 +280,18 @@ class DiagnosticReporter {
/// Report the given [diagnostic].
void reportError(Diagnostic diagnostic) {
_diagnosticListener.onError(diagnostic);
_diagnosticListener.onDiagnostic(diagnostic);
}
}
/// A diagnostic listener that records the diagnostics that are reported to it
/// in a way that is appropriate for caching those diagnostic within an
/// analysis context.
class RecordingDiagnosticListener implements DiagnosticListener {
class RecordingDiagnosticListener
implements
// ignore: deprecated_member_use_from_same_package
AnalysisErrorListener,
DiagnosticListener {
Set<Diagnostic>? _diagnostics;
/// The diagnostics collected by the listener.
@@ -297,17 +315,42 @@ class RecordingDiagnosticListener implements DiagnosticListener {
}
@override
void onError(Diagnostic diagnostic) {
void onDiagnostic(Diagnostic diagnostic) {
(_diagnostics ??= {}).add(diagnostic);
}
@override
void onError(Diagnostic diagnostic) => onDiagnostic(diagnostic);
}
/// A [DiagnosticListener] that ignores everything.
class _NullDiagnosticListener implements DiagnosticListener {
const _NullDiagnosticListener();
@override
void onDiagnostic(Diagnostic diagnostic) {
// Ignore diagnostics.
}
}
/// An [DiagnosticListener] that ignores everything.
class _NullDiagnosticListener implements DiagnosticListener {
const _NullDiagnosticListener();
// ignore: deprecated_member_use_from_same_package
/// An [AnalysisErrorListener] that ignores everything.
class _NullErrorListener
implements
// ignore: deprecated_member_use_from_same_package
AnalysisErrorListener {
const _NullErrorListener();
@override
void onError(Diagnostic diagnostic) {
// Ignore diagnostics.
}
}
extension DiagnosticOrErrorListenerExtension on DiagnosticOrErrorListener {
void onDiagnostic(Diagnostic diagnostic) => switch (this) {
DiagnosticListener self => self.onDiagnostic(diagnostic),
// ignore: deprecated_member_use_from_same_package
AnalysisErrorListener self => self.onError(diagnostic),
};
}
@@ -591,7 +591,8 @@ class FileState {
/// Return a new parsed unresolved [CompilationUnit].
CompilationUnitImpl parse({
DiagnosticListener diagnosticListener = DiagnosticListener.NULL_LISTENER,
DiagnosticOrErrorListener diagnosticListener =
DiagnosticListener.nullListener,
required OperationPerformanceImpl performance,
}) {
try {
@@ -608,7 +609,7 @@ class FileState {
/// Parses given [code] with the same features as this file.
CompilationUnitImpl parseCode({
required String code,
required DiagnosticListener diagnosticListener,
required DiagnosticOrErrorListener diagnosticListener,
required OperationPerformanceImpl performance,
}) {
return performance.run('parseCode', (performance) {
@@ -975,7 +975,7 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
// Ignore any diagnostics produced during validation--if the
// constant can't be evaluated we'll just report a single error.
DiagnosticReporter subDiagnosticReporter = DiagnosticReporter(
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
_diagnosticReporter.source,
);
var result = initializer.accept(
@@ -42,7 +42,7 @@ class Scanner {
/// The diagnostic listener that will be informed of any diagnostics that are
/// found during the scan.
final DiagnosticListener _diagnosticListener;
final DiagnosticOrErrorListener _diagnosticListener;
/// If the file has [fasta.LanguageVersionToken], it is allowed to use the
/// language version greater than the one specified in the package config.
@@ -65,7 +65,7 @@ class Scanner {
factory Scanner(
Source source,
CharacterReader reader,
DiagnosticListener diagnosticListener,
DiagnosticOrErrorListener diagnosticListener,
) => Scanner.fasta(
source,
diagnosticListener,
@@ -75,7 +75,7 @@ class Scanner {
factory Scanner.fasta(
Source source,
DiagnosticListener diagnosticListener, {
DiagnosticOrErrorListener diagnosticListener, {
String? contents,
int offset = -1,
}) {
@@ -128,7 +128,7 @@ class Scanner {
int offset,
List<Object?>? arguments,
) {
_diagnosticListener.onError(
_diagnosticListener.onDiagnostic(
Diagnostic.tmp(
source: source,
offset: offset,
@@ -201,7 +201,7 @@ class Scanner {
var latestVersion = ExperimentStatus.currentVersion;
if (overrideVersion > latestVersion) {
_diagnosticListener.onError(
_diagnosticListener.onDiagnostic(
Diagnostic.tmp(
source: source,
offset: versionToken.offset,
@@ -1011,7 +1011,7 @@ class UnusedLocalElementsVerifier extends RecursiveAstVisitor<void> {
) {
if (element != null) {
var fragment = element.firstFragment;
_diagnosticListener.onError(
_diagnosticListener.onDiagnostic(
Diagnostic.tmp(
source: fragment.libraryFragment!.source,
offset:
+1 -1
View File
@@ -30,7 +30,7 @@ class Parser {
Parser(
Source source,
DiagnosticListener diagnosticListener, {
DiagnosticOrErrorListener diagnosticListener, {
required FeatureSet featureSet,
bool allowNativeClause = true,
required LibraryLanguageVersion languageVersion,
+1 -1
View File
@@ -24,7 +24,7 @@ class _ConstantDiagnosticListener extends DiagnosticListener {
bool hasConstError = false;
@override
void onError(Diagnostic diagnostic) {
void onDiagnostic(Diagnostic diagnostic) {
DiagnosticCode diagnosticCode = diagnostic.diagnosticCode;
if (diagnosticCode is CompileTimeErrorCode) {
switch (diagnosticCode) {
@@ -24,7 +24,7 @@ class AstResolver {
final Scope _nameScope;
final FeatureSet _featureSet;
final DiagnosticListener _diagnosticListener =
DiagnosticListener.NULL_LISTENER;
DiagnosticListener.nullListener;
final AnalysisOptions analysisOptions;
final InterfaceElementImpl? enclosingClassElement;
final ExecutableElementImpl? enclosingExecutableElement;
@@ -1294,7 +1294,7 @@ class ParserTestCase with ParserTestHelpers implements AbstractParserTestCase {
/// Parse the given [content] as a compilation unit.
CompilationUnit parseCompilationUnit2(
String content, {
DiagnosticListener listener = DiagnosticListener.NULL_LISTENER,
DiagnosticOrErrorListener listener = DiagnosticListener.nullListener,
}) {
Source source = NonExistingSource.unknown;
@@ -168,7 +168,7 @@ class GatheringDiagnosticListener implements DiagnosticListener {
/// Adds the given [diagnostics] to this listener.
void addAll(List<Diagnostic> diagnostics) {
for (Diagnostic diagnostic in diagnostics) {
onError(diagnostic);
onDiagnostic(diagnostic);
}
}
@@ -439,7 +439,7 @@ class GatheringDiagnosticListener implements DiagnosticListener {
LineInfo? getLineInfo(Source source) => _lineInfoMap[source];
@override
void onError(Diagnostic diagnostic) {
void onDiagnostic(Diagnostic diagnostic) {
_diagnostics.add(diagnostic);
}
@@ -16,7 +16,7 @@ import 'package:analyzer/src/generated/parser.dart';
CompilationUnit parseText(Source source, String text, FeatureSet featureSet) {
CharSequenceReader reader = CharSequenceReader(text);
Scanner scanner = Scanner(source, reader, DiagnosticListener.NULL_LISTENER)
Scanner scanner = Scanner(source, reader, DiagnosticListener.nullListener)
..configureFeatures(
featureSetForOverriding: featureSet,
featureSet: featureSet,
@@ -28,7 +28,7 @@ CompilationUnit parseText(Source source, String text, FeatureSet featureSet) {
// and downgraded the feature set it holds.
Parser parser = Parser(
source,
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
featureSet: scanner.featureSet,
languageVersion: LibraryLanguageVersion(
package: ExperimentStatus.currentVersion,
+3 -3
View File
@@ -95,7 +95,7 @@ CompilationUnit parseDirectives(Source source) {
var lineInfo = LineInfo(result.lineStarts);
var parser = Parser(
source,
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
featureSet: FeatureSet.latestLanguageVersion(),
lineInfo: lineInfo,
languageVersion: languageVersion,
@@ -136,7 +136,7 @@ CompilationUnit parseFull(Source source) {
var lineInfo = LineInfo(result.lineStarts);
var parser = Parser(
source,
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
featureSet: FeatureSet.latestLanguageVersion(),
languageVersion: languageVersion,
lineInfo: lineInfo,
@@ -238,7 +238,7 @@ ScannerResult tokenize(Source source) {
Scanner(
source,
CharSequenceReader(contents),
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
)
..configureFeatures(
featureSetForOverriding: featureSet,
+3 -3
View File
@@ -24,13 +24,13 @@ import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart' show Folder;
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/source/source.dart';
import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart' show FolderBasedDartSdk;
import 'package:analyzer/src/file_system/file_system.dart';
import 'package:analyzer/src/generated/parser.dart';
@@ -113,7 +113,7 @@ CompilationUnit parseDirectives(Source source) {
var lineInfo = LineInfo(result.lineStarts);
var parser = new Parser(
source,
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
featureSet: FeatureSet.latestLanguageVersion(),
languageVersion: LibraryLanguageVersion(
package: ExperimentStatus.currentVersion, override: null),
@@ -141,7 +141,7 @@ CompilationUnit parseFull(Source source) {
parseTimer.start();
var parser = new Parser(
source,
DiagnosticListener.NULL_LISTENER,
DiagnosticListener.nullListener,
featureSet: FeatureSet.latestLanguageVersion(),
languageVersion: LibraryLanguageVersion(
package: ExperimentStatus.currentVersion, override: null),
@@ -77,7 +77,7 @@ class TestLinter implements DiagnosticListener {
}
@override
void onError(Diagnostic error) => errors.add(error);
void onDiagnostic(Diagnostic error) => errors.add(error);
/// Returns whether this [entry] is a pubspec file.
bool _isPubspecFile(FileSystemEntity entry) =>
+1 -1
View File
@@ -18,7 +18,7 @@ class SimpleDiagnosticListener implements DiagnosticListener {
bool get hadDiagnostic => _hadDiagnostic;
@override
void onError(Diagnostic diagnostic) {
void onDiagnostic(Diagnostic diagnostic) {
_hadDiagnostic = true;
if (_printDiagnostics) {