mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Make FlutterErrorDetails.exception non-nullable as documented (#67364)
This commit is contained in:
parent
1271447bbe
commit
8998167d0f
@ -390,20 +390,20 @@ class FlutterErrorDetails with Diagnosticable {
|
||||
/// their default values. (`throw null` results in a
|
||||
/// [NullThrownError] exception.)
|
||||
const FlutterErrorDetails({
|
||||
this.exception,
|
||||
required this.exception,
|
||||
this.stack,
|
||||
this.library = 'Flutter framework',
|
||||
this.context,
|
||||
this.stackFilter,
|
||||
this.informationCollector,
|
||||
this.silent = false,
|
||||
});
|
||||
}) : assert(exception != null);
|
||||
|
||||
/// Creates a copy of the error details but with the given fields replaced
|
||||
/// with new values.
|
||||
FlutterErrorDetails copyWith({
|
||||
DiagnosticsNode? context,
|
||||
dynamic exception,
|
||||
Object? exception,
|
||||
InformationCollector? informationCollector,
|
||||
String? library,
|
||||
bool? silent,
|
||||
@ -437,7 +437,7 @@ class FlutterErrorDetails with Diagnosticable {
|
||||
|
||||
/// The exception. Often this will be an [AssertionError], maybe specifically
|
||||
/// a [FlutterError]. However, this could be any value at all.
|
||||
final dynamic exception;
|
||||
final Object exception;
|
||||
|
||||
/// The stack trace from where the [exception] was thrown (as opposed to where
|
||||
/// it was caught).
|
||||
@ -552,7 +552,7 @@ class FlutterErrorDetails with Diagnosticable {
|
||||
// some code snippets. This leads to ugly messages. To avoid this, we move
|
||||
// the assertion message up to before the code snippets, separated by a
|
||||
// newline, if we recognize that format is being used.
|
||||
final Object? message = exception.message;
|
||||
final Object? message = (exception as AssertionError).message;
|
||||
final String fullMessage = exception.toString();
|
||||
if (message is String && message != fullMessage) {
|
||||
if (fullMessage.length > message.length) {
|
||||
@ -586,8 +586,9 @@ class FlutterErrorDetails with Diagnosticable {
|
||||
}
|
||||
|
||||
Diagnosticable? _exceptionToDiagnosticable() {
|
||||
final Object exception = this.exception;
|
||||
if (exception is FlutterError) {
|
||||
return exception as FlutterError;
|
||||
return exception;
|
||||
}
|
||||
if (exception is AssertionError && exception.message is FlutterError) {
|
||||
return exception.message as FlutterError;
|
||||
|
@ -539,7 +539,7 @@ abstract class BindingBase {
|
||||
return Future<void>.delayed(Duration.zero);
|
||||
});
|
||||
|
||||
dynamic caughtException;
|
||||
Object? caughtException;
|
||||
StackTrace? caughtStack;
|
||||
late Map<String, dynamic> result;
|
||||
try {
|
||||
|
@ -432,7 +432,7 @@ class FlutterErrorDetailsForPointerEventDispatcher extends FlutterErrorDetails {
|
||||
/// The gesture library calls this constructor when catching an exception
|
||||
/// that will subsequently be reported using [FlutterError.onError].
|
||||
const FlutterErrorDetailsForPointerEventDispatcher({
|
||||
dynamic exception,
|
||||
required Object exception,
|
||||
StackTrace? stack,
|
||||
String? library,
|
||||
DiagnosticsNode? context,
|
||||
|
@ -22,7 +22,7 @@ import 'image_stream.dart';
|
||||
typedef _KeyAndErrorHandlerCallback<T> = void Function(T key, ImageErrorListener handleError);
|
||||
|
||||
/// Signature used for error handling by [_createErrorHandlerAndKey].
|
||||
typedef _AsyncKeyErrorHandler<T> = Future<void> Function(T key, dynamic exception, StackTrace? stack);
|
||||
typedef _AsyncKeyErrorHandler<T> = Future<void> Function(T key, Object exception, StackTrace? stack);
|
||||
|
||||
/// Configuration information passed to the [ImageProvider.resolve] method to
|
||||
/// select a specific image.
|
||||
@ -335,7 +335,7 @@ abstract class ImageProvider<T extends Object> {
|
||||
(T key, ImageErrorListener errorHandler) {
|
||||
resolveStreamForKey(configuration, stream, key, errorHandler);
|
||||
},
|
||||
(T? key, dynamic exception, StackTrace? stack) async {
|
||||
(T? key, Object exception, StackTrace? stack) async {
|
||||
await null; // wait an event turn in case a listener has been added to the image stream.
|
||||
final _ErrorImageCompleter imageCompleter = _ErrorImageCompleter();
|
||||
stream.setCompleter(imageCompleter);
|
||||
@ -391,7 +391,7 @@ abstract class ImageProvider<T extends Object> {
|
||||
(T key, ImageErrorListener innerHandleError) {
|
||||
completer.complete(PaintingBinding.instance!.imageCache!.statusForKey(key));
|
||||
},
|
||||
(T? key, dynamic exception, StackTrace? stack) async {
|
||||
(T? key, Object exception, StackTrace? stack) async {
|
||||
if (handleError != null) {
|
||||
handleError(exception, stack);
|
||||
} else {
|
||||
@ -427,7 +427,7 @@ abstract class ImageProvider<T extends Object> {
|
||||
) {
|
||||
T? obtainedKey;
|
||||
bool didError = false;
|
||||
Future<void> handleError(dynamic exception, StackTrace? stack) async {
|
||||
Future<void> handleError(Object exception, StackTrace? stack) async {
|
||||
if (didError) {
|
||||
return;
|
||||
}
|
||||
@ -1118,7 +1118,7 @@ class _ErrorImageCompleter extends ImageStreamCompleter {
|
||||
|
||||
void setError({
|
||||
DiagnosticsNode? context,
|
||||
dynamic exception,
|
||||
required Object exception,
|
||||
StackTrace? stack,
|
||||
InformationCollector? informationCollector,
|
||||
bool silent = false,
|
||||
|
@ -233,7 +233,7 @@ typedef ImageChunkListener = void Function(ImageChunkEvent event);
|
||||
///
|
||||
/// Used in [ImageStreamListener], as well as by [ImageCache.putIfAbsent] and
|
||||
/// [precacheImage], to report errors.
|
||||
typedef ImageErrorListener = void Function(dynamic exception, StackTrace? stackTrace);
|
||||
typedef ImageErrorListener = void Function(Object exception, StackTrace? stackTrace);
|
||||
|
||||
/// An immutable notification of image bytes that have been incrementally loaded.
|
||||
///
|
||||
@ -655,7 +655,7 @@ abstract class ImageStreamCompleter with Diagnosticable {
|
||||
@protected
|
||||
void reportError({
|
||||
DiagnosticsNode? context,
|
||||
dynamic exception,
|
||||
required Object exception,
|
||||
StackTrace? stack,
|
||||
InformationCollector? informationCollector,
|
||||
bool silent = false,
|
||||
@ -747,7 +747,7 @@ class OneFrameImageStreamCompleter extends ImageStreamCompleter {
|
||||
/// FlutterErrorDetails]).
|
||||
OneFrameImageStreamCompleter(Future<ImageInfo> image, { InformationCollector? informationCollector })
|
||||
: assert(image != null) {
|
||||
image.then<void>(setImage, onError: (dynamic error, StackTrace stack) {
|
||||
image.then<void>(setImage, onError: (Object error, StackTrace stack) {
|
||||
reportError(
|
||||
context: ErrorDescription('resolving a single-frame image stream'),
|
||||
exception: error,
|
||||
@ -819,7 +819,7 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter {
|
||||
_informationCollector = informationCollector,
|
||||
_scale = scale {
|
||||
this.debugLabel = debugLabel;
|
||||
codec.then<void>(_handleCodecReady, onError: (dynamic error, StackTrace stack) {
|
||||
codec.then<void>(_handleCodecReady, onError: (Object error, StackTrace stack) {
|
||||
reportError(
|
||||
context: ErrorDescription('resolving an image codec'),
|
||||
exception: error,
|
||||
@ -830,7 +830,7 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter {
|
||||
});
|
||||
if (chunkEvents != null) {
|
||||
chunkEvents.listen(reportImageChunkEvent,
|
||||
onError: (dynamic error, StackTrace stack) {
|
||||
onError: (Object error, StackTrace stack) {
|
||||
reportError(
|
||||
context: ErrorDescription('loading an image'),
|
||||
exception: error,
|
||||
|
@ -1307,7 +1307,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
|
||||
/// Used in debug messages.
|
||||
Object? debugCreator;
|
||||
|
||||
void _debugReportException(String method, dynamic exception, StackTrace stack) {
|
||||
void _debugReportException(String method, Object exception, StackTrace stack) {
|
||||
FlutterError.reportError(FlutterErrorDetails(
|
||||
exception: exception,
|
||||
stack: stack,
|
||||
|
@ -4526,7 +4526,7 @@ class ErrorWidget extends LeafRenderObjectWidget {
|
||||
message = _stringify(details.exception) + '\nSee also: https://flutter.dev/docs/testing/errors';
|
||||
return true;
|
||||
}());
|
||||
final dynamic exception = details.exception;
|
||||
final Object exception = details.exception;
|
||||
return ErrorWidget.withDetails(message: message, error: exception is FlutterError ? exception : null);
|
||||
}
|
||||
|
||||
@ -6312,7 +6312,7 @@ class DebugCreator {
|
||||
|
||||
FlutterErrorDetails _debugReportException(
|
||||
DiagnosticsNode context,
|
||||
dynamic exception,
|
||||
Object exception,
|
||||
StackTrace? stack, {
|
||||
InformationCollector? informationCollector,
|
||||
}) {
|
||||
|
@ -123,7 +123,7 @@ Future<void> precacheImage(
|
||||
stream.removeListener(listener!);
|
||||
});
|
||||
},
|
||||
onError: (dynamic exception, StackTrace? stackTrace) {
|
||||
onError: (Object exception, StackTrace? stackTrace) {
|
||||
if (!completer.isCompleted) {
|
||||
completer.complete();
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
|
||||
|
||||
FlutterErrorDetails _debugReportException(
|
||||
DiagnosticsNode context,
|
||||
dynamic exception,
|
||||
Object exception,
|
||||
StackTrace stack, {
|
||||
InformationCollector? informationCollector,
|
||||
}) {
|
||||
|
@ -1670,7 +1670,7 @@ class KeepAlive extends ParentDataWidget<KeepAliveParentDataMixin> {
|
||||
}
|
||||
|
||||
// Return a Widget for the given Exception
|
||||
Widget _createErrorWidget(dynamic exception, StackTrace stackTrace) {
|
||||
Widget _createErrorWidget(Object exception, StackTrace stackTrace) {
|
||||
final FlutterErrorDetails details = FlutterErrorDetails(
|
||||
exception: exception,
|
||||
stack: stackTrace,
|
||||
|
@ -57,10 +57,10 @@ void main() {
|
||||
'\n'
|
||||
'INFO\n'
|
||||
'═════════════════════════════════════════════════════════════════\n',
|
||||
|
||||
);
|
||||
expect(
|
||||
FlutterErrorDetails(
|
||||
exception: NullThrownError(),
|
||||
library: 'LIBRARY',
|
||||
context: ErrorDescription('CONTEXTING'),
|
||||
informationCollector: () sync* {
|
||||
@ -68,11 +68,10 @@ void main() {
|
||||
},
|
||||
).toString(),
|
||||
'══╡ EXCEPTION CAUGHT BY LIBRARY ╞════════════════════════════════\n'
|
||||
'The following Null object was thrown CONTEXTING:\n'
|
||||
' null\n'
|
||||
'The null value was thrown CONTEXTING.\n'
|
||||
'\n'
|
||||
'INFO\n'
|
||||
'═════════════════════════════════════════════════════════════════\n',
|
||||
'═════════════════════════════════════════════════════════════════\n'
|
||||
);
|
||||
expect(
|
||||
FlutterErrorDetails(
|
||||
@ -114,11 +113,10 @@ void main() {
|
||||
'═════════════════════════════════════════════════════════════════\n',
|
||||
);
|
||||
expect(
|
||||
const FlutterErrorDetails().toString(),
|
||||
FlutterErrorDetails(exception: NullThrownError()).toString(),
|
||||
'══╡ EXCEPTION CAUGHT BY FLUTTER FRAMEWORK ╞══════════════════════\n'
|
||||
'The following Null object was thrown:\n'
|
||||
' null\n'
|
||||
'═════════════════════════════════════════════════════════════════\n',
|
||||
'The null value was thrown.\n'
|
||||
'═════════════════════════════════════════════════════════════════\n'
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../flutter_test_alternative.dart';
|
||||
|
||||
dynamic getAssertionErrorWithMessage() {
|
||||
Object getAssertionErrorWithMessage() {
|
||||
try {
|
||||
assert(false, 'Message goes here.');
|
||||
} catch (e) {
|
||||
@ -16,7 +16,7 @@ dynamic getAssertionErrorWithMessage() {
|
||||
throw 'assert failed';
|
||||
}
|
||||
|
||||
dynamic getAssertionErrorWithoutMessage() {
|
||||
Object getAssertionErrorWithoutMessage() {
|
||||
try {
|
||||
assert(false);
|
||||
} catch (e) {
|
||||
@ -25,7 +25,7 @@ dynamic getAssertionErrorWithoutMessage() {
|
||||
throw 'assert failed';
|
||||
}
|
||||
|
||||
dynamic getAssertionErrorWithLongMessage() {
|
||||
Object getAssertionErrorWithLongMessage() {
|
||||
try {
|
||||
assert(false, 'word ' * 100);
|
||||
} catch (e) {
|
||||
|
@ -117,7 +117,7 @@ void main() {
|
||||
});
|
||||
expect(errors, hasLength(2));
|
||||
expect(errors.first.exception, isFlutterError);
|
||||
expect(errors.first.exception.toStringDeep(),
|
||||
expect((errors.first.exception as FlutterError).toStringDeep(),
|
||||
'FlutterError\n'
|
||||
' RenderAspectRatio has unbounded constraints.\n'
|
||||
' This RenderAspectRatio was given an aspect ratio of 0.5 but was\n'
|
||||
|
@ -27,7 +27,7 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser
|
||||
TestRenderingFlutterBinding({ this.onErrors }) {
|
||||
FlutterError.onError = (FlutterErrorDetails details) {
|
||||
FlutterError.dumpErrorToConsole(details);
|
||||
Zone.current.parent!.handleUncaughtError(details.exception as Object, details.stack!);
|
||||
Zone.current.parent!.handleUncaughtError(details.exception, details.stack!);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1627,7 +1627,7 @@ void main() {
|
||||
}
|
||||
expect(errors, isNotEmpty);
|
||||
expect(errors.first.exception, isFlutterError);
|
||||
expect(errors.first.exception.toStringDeep(), message);
|
||||
expect((errors.first.exception as FlutterError).toStringDeep(), message);
|
||||
}
|
||||
|
||||
testWidgets('Horizontal viewport was given unbounded height', (WidgetTester tester) async {
|
||||
|
@ -301,7 +301,7 @@ void main() {
|
||||
expect(errors.length, isNonZero);
|
||||
expect(errors.first, isNotNull);
|
||||
expect(errors.first.exception, isFlutterError);
|
||||
expect(errors.first.exception.toStringDeep(), equalsIgnoringHashCodes(message));
|
||||
expect((errors.first.exception as FlutterError).toStringDeep(), equalsIgnoringHashCodes(message));
|
||||
}
|
||||
|
||||
testWidgets('layoutChild on non existent child', (WidgetTester tester) async {
|
||||
|
@ -134,7 +134,7 @@ void main() {
|
||||
}
|
||||
expect(errors, isNotEmpty);
|
||||
expect(errors.first.exception, isFlutterError);
|
||||
expect(errors.first.exception.toStringDeep(), equalsIgnoringHashCodes(
|
||||
expect((errors.first.exception as FlutterError).toStringDeep(), equalsIgnoringHashCodes(
|
||||
'FlutterError\n'
|
||||
' RenderListBody must have unlimited space along its main axis.\n'
|
||||
' RenderListBody does not clip or resize its children, so it must\n'
|
||||
@ -183,7 +183,7 @@ void main() {
|
||||
}
|
||||
expect(errors, isNotEmpty);
|
||||
expect(errors.first.exception, isFlutterError);
|
||||
expect(errors.first.exception.toStringDeep(), equalsIgnoringHashCodes(
|
||||
expect((errors.first.exception as FlutterError).toStringDeep(), equalsIgnoringHashCodes(
|
||||
'FlutterError\n'
|
||||
' RenderListBody must have a bounded constraint for its cross axis.\n'
|
||||
' RenderListBody forces its children to expand to fit the\n'
|
||||
|
@ -686,7 +686,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
};
|
||||
final Completer<void> testCompleter = Completer<void>();
|
||||
final VoidCallback testCompletionHandler = _createTestCompletionHandler(description, testCompleter);
|
||||
void handleUncaughtError(dynamic exception, StackTrace stack) {
|
||||
void handleUncaughtError(Object exception, StackTrace stack) {
|
||||
if (testCompleter.isCompleted) {
|
||||
// Well this is not a good sign.
|
||||
// Ideally, once the test has failed we would stop getting errors from the test.
|
||||
@ -765,7 +765,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
_parentZone!.run<void>(testCompletionHandler);
|
||||
}
|
||||
final ZoneSpecification errorHandlingZoneSpecification = ZoneSpecification(
|
||||
handleUncaughtError: (Zone self, ZoneDelegate parent, Zone zone, dynamic exception, StackTrace stack) {
|
||||
handleUncaughtError: (Zone self, ZoneDelegate parent, Zone zone, Object exception, StackTrace stack) {
|
||||
handleUncaughtError(exception, stack);
|
||||
}
|
||||
);
|
||||
@ -1013,7 +1013,7 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
||||
|
||||
return realAsyncZone.run<Future<T>>(() {
|
||||
_pendingAsyncTasks = Completer<void>();
|
||||
return callback().catchError((dynamic exception, StackTrace stack) {
|
||||
return callback().catchError((Object exception, StackTrace stack) {
|
||||
FlutterError.reportError(FlutterErrorDetails(
|
||||
exception: exception,
|
||||
stack: stack,
|
||||
|
@ -28,7 +28,7 @@ Future<void> main() async {
|
||||
|
||||
completer.future.then(
|
||||
(String value) {},
|
||||
onError: (dynamic error, StackTrace stack) {
|
||||
onError: (Object error, StackTrace stack) {
|
||||
assert(stack is stack_trace.Chain);
|
||||
FlutterError.reportError(FlutterErrorDetails(
|
||||
exception: error,
|
||||
|
@ -10,7 +10,7 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
Future<void> main(FutureOr<void> testMain()) async {
|
||||
reportTestException = (FlutterErrorDetails details, String testDescription) {
|
||||
expect(details.exception, isA<StateError>());
|
||||
expect(details.exception.message, 'foo');
|
||||
expect((details.exception as StateError).message, 'foo');
|
||||
expect(testDescription, 'custom exception reporter');
|
||||
};
|
||||
|
||||
|
@ -737,7 +737,7 @@ void main() {
|
||||
}, () {});
|
||||
|
||||
expect(flutterErrorDetails.exception, isA<AssertionError>());
|
||||
expect(flutterErrorDetails.exception!.message, 'A Timer is still pending even after the widget tree was disposed.');
|
||||
expect((flutterErrorDetails.exception as AssertionError).message, 'A Timer is still pending even after the widget tree was disposed.');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user