Unverified Commit 8998167d authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Make FlutterErrorDetails.exception non-nullable as documented (#67364)

parent 1271447b
......@@ -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.');
});
});
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment