Unverified Commit 299d4849 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Enable more lints (#91642)

parent 9570d353
...@@ -56,10 +56,10 @@ linter: ...@@ -56,10 +56,10 @@ linter:
- annotate_overrides - annotate_overrides
# - avoid_annotating_with_dynamic # conflicts with always_specify_types # - avoid_annotating_with_dynamic # conflicts with always_specify_types
- avoid_bool_literals_in_conditional_expressions - avoid_bool_literals_in_conditional_expressions
# - avoid_catches_without_on_clauses # we do this commonly # - avoid_catches_without_on_clauses # blocked on https://github.com/dart-lang/linter/issues/3023
# - avoid_catching_errors # we do this commonly # - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023
- avoid_classes_with_only_static_members - avoid_classes_with_only_static_members
# - avoid_double_and_int_checks # only useful when targeting JS runtime - avoid_double_and_int_checks
- avoid_dynamic_calls - avoid_dynamic_calls
- avoid_empty_else - avoid_empty_else
- avoid_equals_and_hash_code_on_mutable_classes - avoid_equals_and_hash_code_on_mutable_classes
...@@ -68,7 +68,7 @@ linter: ...@@ -68,7 +68,7 @@ linter:
- avoid_function_literals_in_foreach_calls - avoid_function_literals_in_foreach_calls
- avoid_implementing_value_types - avoid_implementing_value_types
- avoid_init_to_null - avoid_init_to_null
# - avoid_js_rounded_ints # only useful when targeting JS runtime - avoid_js_rounded_ints
# - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to
- avoid_null_checks_in_equality_operators - avoid_null_checks_in_equality_operators
# - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it # - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it
...@@ -81,7 +81,7 @@ linter: ...@@ -81,7 +81,7 @@ linter:
# - avoid_returning_null # still violated by some pre-nnbd code that we haven't yet migrated # - avoid_returning_null # still violated by some pre-nnbd code that we haven't yet migrated
- avoid_returning_null_for_future - avoid_returning_null_for_future
- avoid_returning_null_for_void - avoid_returning_null_for_void
# - avoid_returning_this # there are plenty of valid reasons to return this # - avoid_returning_this # there are enough valid reasons to return `this` that this lint ends up with too many false positives
- avoid_setters_without_getters - avoid_setters_without_getters
- avoid_shadowing_type_parameters - avoid_shadowing_type_parameters
- avoid_single_cascade_in_expression_statements - avoid_single_cascade_in_expression_statements
...@@ -201,7 +201,7 @@ linter: ...@@ -201,7 +201,7 @@ linter:
- tighten_type_of_initializing_formals - tighten_type_of_initializing_formals
# - type_annotate_public_apis # subset of always_specify_types # - type_annotate_public_apis # subset of always_specify_types
- type_init_formals - type_init_formals
# - unawaited_futures # too many false positives # - unawaited_futures # too many false positives, especially with the way AnimationController works
- unnecessary_await_in_return - unnecessary_await_in_return
- unnecessary_brace_in_string_interps - unnecessary_brace_in_string_interps
- unnecessary_const - unnecessary_const
...@@ -216,24 +216,24 @@ linter: ...@@ -216,24 +216,24 @@ linter:
- unnecessary_nullable_for_final_variable_declarations - unnecessary_nullable_for_final_variable_declarations
- unnecessary_overrides - unnecessary_overrides
- unnecessary_parenthesis - unnecessary_parenthesis
# - unnecessary_raw_strings # not yet tested # - unnecessary_raw_strings # what's "necessary" is a matter of opinion; consistency across strings can help readability more than this lint
- unnecessary_statements - unnecessary_statements
- unnecessary_string_escapes - unnecessary_string_escapes
- unnecessary_string_interpolations - unnecessary_string_interpolations
- unnecessary_this - unnecessary_this
- unrelated_type_equality_checks - unrelated_type_equality_checks
# - unsafe_html # not yet tested - unsafe_html
- use_build_context_synchronously - use_build_context_synchronously
- use_full_hex_values_for_flutter_colors - use_full_hex_values_for_flutter_colors
- use_function_type_syntax_for_parameters - use_function_type_syntax_for_parameters
# - use_if_null_to_convert_nulls_to_bools # not yet tested # - use_if_null_to_convert_nulls_to_bools # blocked on https://github.com/dart-lang/sdk/issues/47436
- use_is_even_rather_than_modulo - use_is_even_rather_than_modulo
- use_key_in_widget_constructors - use_key_in_widget_constructors
- use_late_for_private_fields_and_variables - use_late_for_private_fields_and_variables
- use_named_constants - use_named_constants
- use_raw_strings - use_raw_strings
- use_rethrow_when_possible - use_rethrow_when_possible
# - use_setters_to_change_properties # not yet tested - use_setters_to_change_properties
# - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182
- use_test_throws_matchers - use_test_throws_matchers
# - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review
......
...@@ -2,5 +2,10 @@ include: ../analysis_options.yaml ...@@ -2,5 +2,10 @@ include: ../analysis_options.yaml
linter: linter:
rules: rules:
avoid_print: false # We use prints as debugging tools here all the time. avoid_print: false # We use prints as debugging tools here a lot.
only_throw_errors: false # Tests use a less... rigorous style.
# Tests try to throw and catch things in exciting ways all the time, so
# we disable these lints for the tests.
only_throw_errors: false
avoid_catching_errors: false
avoid_catches_without_on_clauses: false
include: ../analysis_options.yaml
linter:
rules:
avoid_js_rounded_ints: false # CLI code doesn't need to worry about JS issues
...@@ -46,7 +46,7 @@ class Calculator { ...@@ -46,7 +46,7 @@ class Calculator {
final List<dynamic> result = decoder.convert(_data) as List<dynamic>; final List<dynamic> result = decoder.convert(_data) as List<dynamic>;
final int n = result.length; final int n = result.length;
onResultListener('Decoded $n results'); onResultListener('Decoded $n results');
} catch (e, stack) { } on FormatException catch (e, stack) {
debugPrint('Invalid JSON file: $e'); debugPrint('Invalid JSON file: $e');
debugPrint('$stack'); debugPrint('$stack');
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import 'bitfield.dart' as bitfield; import 'bitfield.dart' as bitfield;
/// The dart:io implementation of [bitfield.kMaxUnsignedSMI]. /// The dart:io implementation of [bitfield.kMaxUnsignedSMI].
const int kMaxUnsignedSMI = 0x3FFFFFFFFFFFFFFF; const int kMaxUnsignedSMI = 0x3FFFFFFFFFFFFFFF; // ignore: avoid_js_rounded_ints, (VM-only code)
/// The dart:io implementation of [bitfield.Bitfield]. /// The dart:io implementation of [bitfield.Bitfield].
class BitField<T extends dynamic> implements bitfield.BitField<T> { class BitField<T extends dynamic> implements bitfield.BitField<T> {
......
...@@ -597,34 +597,27 @@ abstract class BindingBase { ...@@ -597,34 +597,27 @@ abstract class BindingBase {
return Future<void>.delayed(Duration.zero); return Future<void>.delayed(Duration.zero);
}); });
Object? caughtException;
StackTrace? caughtStack;
late Map<String, dynamic> result; late Map<String, dynamic> result;
try { try {
result = await callback(parameters); result = await callback(parameters);
} catch (exception, stack) { } catch (exception, stack) {
caughtException = exception;
caughtStack = stack;
}
if (caughtException == null) {
result['type'] = '_extensionType';
result['method'] = method;
return developer.ServiceExtensionResponse.result(json.encode(result));
} else {
FlutterError.reportError(FlutterErrorDetails( FlutterError.reportError(FlutterErrorDetails(
exception: caughtException, exception: exception,
stack: caughtStack, stack: stack,
context: ErrorDescription('during a service extension callback for "$method"'), context: ErrorDescription('during a service extension callback for "$method"'),
)); ));
return developer.ServiceExtensionResponse.error( return developer.ServiceExtensionResponse.error(
developer.ServiceExtensionResponse.extensionError, developer.ServiceExtensionResponse.extensionError,
json.encode(<String, String>{ json.encode(<String, String>{
'exception': caughtException.toString(), 'exception': exception.toString(),
'stack': caughtStack.toString(), 'stack': stack.toString(),
'method': method, 'method': method,
}), }),
); );
} }
result['type'] = '_extensionType';
result['method'] = method;
return developer.ServiceExtensionResponse.result(json.encode(result));
}); });
} }
......
...@@ -2832,6 +2832,8 @@ class DiagnosticsProperty<T> extends DiagnosticsNode { ...@@ -2832,6 +2832,8 @@ class DiagnosticsProperty<T> extends DiagnosticsNode {
try { try {
_value = _computeValue!(); _value = _computeValue!();
} catch (exception) { } catch (exception) {
// The error is reported to inspector; rethrowing would destroy the
// debugging experience.
_exception = exception; _exception = exception;
_value = null; _value = null;
} }
......
...@@ -1091,6 +1091,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, ...@@ -1091,6 +1091,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
/// The prompt rectangle will only be requested on non-web iOS applications. /// The prompt rectangle will only be requested on non-web iOS applications.
/// ///
/// When set to null, the currently displayed prompt rectangle (if any) will be dismissed. /// When set to null, the currently displayed prompt rectangle (if any) will be dismissed.
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
void setPromptRectRange(TextRange? newRange) { void setPromptRectRange(TextRange? newRange) {
_autocorrectHighlightPainter.highlightedRange = newRange; _autocorrectHighlightPainter.highlightedRange = newRange;
} }
......
...@@ -49,7 +49,9 @@ class RenderErrorBox extends RenderBox { ...@@ -49,7 +49,9 @@ class RenderErrorBox extends RenderBox {
_paragraph = null; _paragraph = null;
} }
} catch (error) { } catch (error) {
// Intentionally left empty. // If an error happens here we're in a terrible state, so we really should
// just forget about it and let the developer deal with the already-reported
// errors. It's unlikely that these errors are going to help with that.
} }
} }
...@@ -161,8 +163,10 @@ class RenderErrorBox extends RenderBox { ...@@ -161,8 +163,10 @@ class RenderErrorBox extends RenderBox {
} }
context.canvas.drawParagraph(_paragraph!, offset + Offset(left, top)); context.canvas.drawParagraph(_paragraph!, offset + Offset(left, top));
} }
} catch (e) { } catch (error) {
// Intentionally left empty. // If an error happens here we're in a terrible state, so we really should
// just forget about it and let the developer deal with the already-reported
// errors. It's unlikely that these errors are going to help with that.
} }
} }
} }
...@@ -640,6 +640,7 @@ abstract class RenderSliverFloatingPersistentHeader extends RenderSliverPersiste ...@@ -640,6 +640,7 @@ abstract class RenderSliverFloatingPersistentHeader extends RenderSliverPersiste
} }
/// Update the last known ScrollDirection when scrolling began. /// Update the last known ScrollDirection when scrolling began.
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
void updateScrollStartDirection(ScrollDirection direction) { void updateScrollStartDirection(ScrollDirection direction) {
_lastStartedScrollDirection = direction; _lastStartedScrollDirection = direction;
} }
......
...@@ -319,6 +319,7 @@ mixin ServicesBinding on BindingBase, SchedulerBinding { ...@@ -319,6 +319,7 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
/// ///
/// * [SystemChrome.setEnabledSystemUIMode], which specifies the /// * [SystemChrome.setEnabledSystemUIMode], which specifies the
/// [SystemUiMode] to have visible when the application is running. /// [SystemUiMode] to have visible when the application is running.
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
void setSystemUiChangeCallback(SystemUiChangeCallback? callback) { void setSystemUiChangeCallback(SystemUiChangeCallback? callback) {
_systemUiChangeCallback = callback; _systemUiChangeCallback = callback;
} }
...@@ -387,7 +388,6 @@ class _DefaultBinaryMessenger extends BinaryMessenger { ...@@ -387,7 +388,6 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
try { try {
response = await handler(data); response = await handler(data);
} catch (exception, stack) { } catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails( FlutterError.reportError(FlutterErrorDetails(
exception: exception, exception: exception,
stack: stack, stack: stack,
......
...@@ -376,7 +376,7 @@ class StandardMessageCodec implements MessageCodec<Object?> { ...@@ -376,7 +376,7 @@ class StandardMessageCodec implements MessageCodec<Object?> {
// decoding because we use tags to detect the type of value. // decoding because we use tags to detect the type of value.
buffer.putUint8(_valueFloat64); buffer.putUint8(_valueFloat64);
buffer.putFloat64(value); buffer.putFloat64(value);
} else if (value is int) { } else if (value is int) { // ignore: avoid_double_and_int_checks, JS code always goes through the `double` path above
if (-0x7fffffff - 1 <= value && value <= 0x7fffffff) { if (-0x7fffffff - 1 <= value && value <= 0x7fffffff) {
buffer.putUint8(_valueInt32); buffer.putUint8(_valueInt32);
buffer.putInt32(value); buffer.putInt32(value);
......
...@@ -410,8 +410,8 @@ class MethodChannel { ...@@ -410,8 +410,8 @@ class MethodChannel {
); );
} on MissingPluginException { } on MissingPluginException {
return null; return null;
} catch (e) { } catch (error) {
return codec.encodeErrorEnvelope(code: 'error', message: e.toString()); return codec.encodeErrorEnvelope(code: 'error', message: error.toString());
} }
} }
......
...@@ -1006,7 +1006,9 @@ bool debugIsSerializableForRestoration(Object? object) { ...@@ -1006,7 +1006,9 @@ bool debugIsSerializableForRestoration(Object? object) {
try { try {
const StandardMessageCodec().encodeMessage(object); const StandardMessageCodec().encodeMessage(object);
result = true; result = true;
} catch (_) { } catch (error) {
// This is only used in asserts, so reporting the exception isn't
// particularly useful, since the assert itself will likely fail.
result = false; result = false;
} }
return true; return true;
......
...@@ -160,6 +160,7 @@ abstract class Action<T extends Intent> with Diagnosticable { ...@@ -160,6 +160,7 @@ abstract class Action<T extends Intent> with Diagnosticable {
final ObserverList<ActionListenerCallback> _listeners = ObserverList<ActionListenerCallback>(); final ObserverList<ActionListenerCallback> _listeners = ObserverList<ActionListenerCallback>();
Action<T>? _currentCallingAction; Action<T>? _currentCallingAction;
// ignore: use_setters_to_change_properties, (code predates enabling of this lint)
void _updateCallingAction(Action<T>? value) { void _updateCallingAction(Action<T>? value) {
_currentCallingAction = value; _currentCallingAction = value;
} }
......
...@@ -2342,6 +2342,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -2342,6 +2342,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
} }
Rect? _currentCaretRect; Rect? _currentCaretRect;
// ignore: use_setters_to_change_properties, (this is used as a callback, can't be a setter)
void _handleCaretChanged(Rect caretRect) { void _handleCaretChanged(Rect caretRect) {
_currentCaretRect = caretRect; _currentCaretRect = caretRect;
} }
......
...@@ -421,6 +421,7 @@ class FormFieldState<T> extends State<FormField<T>> with RestorationMixin { ...@@ -421,6 +421,7 @@ class FormFieldState<T> extends State<FormField<T>> with RestorationMixin {
/// the value should be set by a call to [didChange], which ensures that /// the value should be set by a call to [didChange], which ensures that
/// `setState` is called. /// `setState` is called.
@protected @protected
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
void setValue(T? value) { void setValue(T? value) {
_value = value; _value = value;
} }
......
...@@ -4453,8 +4453,10 @@ class ErrorWidget extends LeafRenderObjectWidget { ...@@ -4453,8 +4453,10 @@ class ErrorWidget extends LeafRenderObjectWidget {
static String _stringify(Object? exception) { static String _stringify(Object? exception) {
try { try {
return exception.toString(); return exception.toString();
} catch (e) { } catch (error) {
// intentionally left empty. // If we get here, it means things have really gone off the rails, and we're better
// off just returning a simple string and letting the developer find out what the
// root cause of all their problems are by looking at the console logs.
} }
return 'Error'; return 'Error';
} }
...@@ -5426,6 +5428,9 @@ abstract class RenderObjectElement extends Element { ...@@ -5426,6 +5428,9 @@ abstract class RenderObjectElement extends Element {
if (badAncestors.isNotEmpty) { if (badAncestors.isNotEmpty) {
badAncestors.insert(0, result); badAncestors.insert(0, result);
try { try {
// We explicitly throw here (even though we immediately redirect the
// exception elsewhere) so that debuggers will notice it when they
// have "break on exception" enabled.
throw FlutterError.fromParts(<DiagnosticsNode>[ throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('Incorrect use of ParentDataWidget.'), ErrorSummary('Incorrect use of ParentDataWidget.'),
ErrorDescription('The following ParentDataWidgets are providing parent data to the same RenderObject:'), ErrorDescription('The following ParentDataWidgets are providing parent data to the same RenderObject:'),
...@@ -5763,9 +5768,10 @@ abstract class RenderObjectElement extends Element { ...@@ -5763,9 +5768,10 @@ abstract class RenderObjectElement extends Element {
]); ]);
} }
} on FlutterError catch (e) { } on FlutterError catch (e) {
// Catching the exception directly to avoid activating the ErrorWidget. // We catch the exception directly to avoid activating the ErrorWidget,
// Since the tree is in a broken state, adding the ErrorWidget would // while still allowing debuggers to break on exception. Since the tree
// cause more exceptions. // is in a broken state, adding the ErrorWidget would likely cause more
// exceptions, which is not good for the debugging experience.
_debugReportException(ErrorSummary('while applying parent data.'), e, e.stackTrace); _debugReportException(ErrorSummary('while applying parent data.'), e, e.stackTrace);
} }
return true; return true;
...@@ -6036,6 +6042,7 @@ abstract class RootRenderObjectElement extends RenderObjectElement { ...@@ -6036,6 +6042,7 @@ abstract class RootRenderObjectElement extends RenderObjectElement {
/// to [runApp]. The binding is responsible for driving the build pipeline by /// to [runApp]. The binding is responsible for driving the build pipeline by
/// calling the build owner's [BuildOwner.buildScope] method. See /// calling the build owner's [BuildOwner.buildScope] method. See
/// [WidgetsBinding.drawFrame]. /// [WidgetsBinding.drawFrame].
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
void assignOwner(BuildOwner owner) { void assignOwner(BuildOwner owner) {
_owner = owner; _owner = owner;
} }
......
...@@ -175,6 +175,7 @@ abstract class Route<T> { ...@@ -175,6 +175,7 @@ abstract class Route<T> {
} }
} }
// ignore: use_setters_to_change_properties, (setters can't be private)
void _updateRestorationId(String? restorationId) { void _updateRestorationId(String? restorationId) {
_restorationScopeId.value = restorationId; _restorationScopeId.value = restorationId;
} }
......
...@@ -320,6 +320,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics { ...@@ -320,6 +320,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
/// middle of layout and applying the new position immediately. /// middle of layout and applying the new position immediately.
/// * [animateTo], which is like [jumpTo] but animating to the /// * [animateTo], which is like [jumpTo] but animating to the
/// destination offset. /// destination offset.
// ignore: use_setters_to_change_properties, (API is intended to discourage setting value)
void correctPixels(double value) { void correctPixels(double value) {
_pixels = value; _pixels = value;
} }
......
...@@ -1277,7 +1277,10 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -1277,7 +1277,10 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
assert (() { assert (() {
try { try {
scrollController!.position; scrollController!.position;
} catch (_) { } catch (error) {
if (scrollController == null || scrollController.positions.length <= 1) {
rethrow;
}
throw FlutterError.fromParts(<DiagnosticsNode>[ throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary( ErrorSummary(
'The $controllerForError is currently attached to more than one ' 'The $controllerForError is currently attached to more than one '
......
...@@ -204,6 +204,7 @@ abstract class SliverChildDelegate { ...@@ -204,6 +204,7 @@ abstract class SliverChildDelegate {
if (children != null) if (children != null)
description.add('estimated child count: $children'); description.add('estimated child count: $children');
} catch (e) { } catch (e) {
// The exception is forwarded to widget inspector.
description.add('estimated child count: EXCEPTION (${e.runtimeType})'); description.add('estimated child count: EXCEPTION (${e.runtimeType})');
} }
} }
......
...@@ -1587,7 +1587,13 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget ...@@ -1587,7 +1587,13 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget
final bool hasStrings; final bool hasStrings;
try { try {
hasStrings = await Clipboard.hasStrings(); hasStrings = await Clipboard.hasStrings();
} catch (stacktrace) { } catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'widget library',
context: ErrorDescription('while checking if the clipboard has strings'),
));
// In the case of an error from the Clipboard API, set the value to // In the case of an error from the Clipboard API, set the value to
// unknown so that it will try to update again later. // unknown so that it will try to update again later.
if (_disposed || value == ClipboardStatus.unknown) { if (_disposed || value == ClipboardStatus.unknown) {
......
...@@ -1962,6 +1962,8 @@ mixin WidgetInspectorService { ...@@ -1962,6 +1962,8 @@ mixin WidgetInspectorService {
FlutterErrorDetails( FlutterErrorDetails(
exception: exception, exception: exception,
stack: stack, stack: stack,
library: 'widget inspector library',
context: ErrorDescription('while tracking widget repaints'),
), ),
); );
} }
......
...@@ -2,4 +2,8 @@ include: ../analysis_options.yaml ...@@ -2,4 +2,8 @@ include: ../analysis_options.yaml
linter: linter:
rules: rules:
only_throw_errors: false # We are more flexible for tests. # Tests try to throw and catch things in exciting ways all the time, so
# we disable these lints for the tests.
only_throw_errors: false
avoid_catches_without_on_clauses: false
avoid_catching_errors: false
...@@ -18,7 +18,7 @@ void main() { ...@@ -18,7 +18,7 @@ void main() {
checkEncodeDecode<dynamic>(json, -9223372036854775807); checkEncodeDecode<dynamic>(json, -9223372036854775807);
}); });
test('should encode and decode list with a big number', () { test('should encode and decode list with a big number', () {
final List<dynamic> message = <dynamic>[-7000000000000000007]; final List<dynamic> message = <dynamic>[-7000000000000000007]; // ignore: avoid_js_rounded_ints, since we check for round-tripping, the actual value doesn't matter!
checkEncodeDecode<dynamic>(json, message); checkEncodeDecode<dynamic>(json, message);
}); });
}); });
...@@ -72,7 +72,7 @@ void main() { ...@@ -72,7 +72,7 @@ void main() {
}); });
test('should encode and decode a list containing big numbers', () { test('should encode and decode a list containing big numbers', () {
final List<dynamic> message = <dynamic>[ final List<dynamic> message = <dynamic>[
-7000000000000000007, -7000000000000000007, // ignore: avoid_js_rounded_ints, browsers are skipped below
Int64List.fromList(<int>[-0x7fffffffffffffff - 1, 0, 0x7fffffffffffffff]), Int64List.fromList(<int>[-0x7fffffffffffffff - 1, 0, 0x7fffffffffffffff]),
]; ];
checkEncodeDecode<dynamic>(standard, message); checkEncodeDecode<dynamic>(standard, message);
......
...@@ -564,6 +564,8 @@ Future<vms.VmService> _waitAndConnect(String url, Map<String, dynamic>? headers) ...@@ -564,6 +564,8 @@ Future<vms.VmService> _waitAndConnect(String url, Map<String, dynamic>? headers)
await service.getVersion(); await service.getVersion();
return service; return service;
} catch (e) { } catch (e) {
// We should not be catching all errors arbitrarily here, this might hide real errors.
// TODO(ianh): Determine which exceptions to catch here.
await socket?.close(); await socket?.close();
if (attempts > 5) { if (attempts > 5) {
_log('It is taking an unusually long time to connect to the VM...'); _log('It is taking an unusually long time to connect to the VM...');
......
...@@ -115,9 +115,10 @@ class WebFlutterDriver extends FlutterDriver { ...@@ -115,9 +115,10 @@ class WebFlutterDriver extends FlutterDriver {
response = data != null ? (json.decode(data as String) as Map<String, dynamic>?)! : <String, dynamic>{}; response = data != null ? (json.decode(data as String) as Map<String, dynamic>?)! : <String, dynamic>{};
_logCommunication('<<< $response'); _logCommunication('<<< $response');
} catch (error, stackTrace) { } catch (error, stackTrace) {
throw DriverError("Failed to respond to $command due to remote error\n : \$flutterDriver('${jsonEncode(serialized)}')", throw DriverError(
error, "Failed to respond to $command due to remote error\n : \$flutterDriver('${jsonEncode(serialized)}')",
stackTrace error,
stackTrace
); );
} }
if (response['isError'] == true) if (response['isError'] == true)
...@@ -261,8 +262,10 @@ class FlutterWebConnection { ...@@ -261,8 +262,10 @@ class FlutterWebConnection {
dynamic result; dynamic result;
try { try {
await _driver.execute(script, <void>[]); await _driver.execute(script, <void>[]);
} catch (_) { } catch (error) {
// In case there is an exception, do nothing // We should not just arbitrarily throw all exceptions on the ground.
// This is probably hiding real errors.
// TODO(ianh): Determine what exceptions are expected here and handle those specifically.
} }
try { try {
...@@ -271,7 +274,10 @@ class FlutterWebConnection { ...@@ -271,7 +274,10 @@ class FlutterWebConnection {
matcher: isNotNull, matcher: isNotNull,
timeout: duration ?? const Duration(days: 30), timeout: duration ?? const Duration(days: 30),
); );
} catch (_) { } catch (error) {
// We should not just arbitrarily throw all exceptions on the ground.
// This is probably hiding real errors.
// TODO(ianh): Determine what exceptions are expected here and handle those specifically.
// Returns null if exception thrown. // Returns null if exception thrown.
return null; return null;
} finally { } finally {
......
...@@ -329,15 +329,9 @@ class SkiaGoldClient { ...@@ -329,15 +329,9 @@ class SkiaGoldClient {
final Uri requestForImage = Uri.parse( final Uri requestForImage = Uri.parse(
'https://flutter-gold.skia.org/img/images/$imageHash.png', 'https://flutter-gold.skia.org/img/images/$imageHash.png',
); );
final io.HttpClientRequest request = await httpClient.getUrl(requestForImage);
try { final io.HttpClientResponse response = await request.close();
final io.HttpClientRequest request = await httpClient.getUrl(requestForImage); await response.forEach((List<int> bytes) => imageBytes.addAll(bytes));
final io.HttpClientResponse response = await request.close();
await response.forEach((List<int> bytes) => imageBytes.addAll(bytes));
} catch(e) {
rethrow;
}
}, },
SkiaGoldHttpOverrides(), SkiaGoldHttpOverrides(),
); );
......
...@@ -743,8 +743,10 @@ abstract class TestWidgetsFlutterBinding extends BindingBase ...@@ -743,8 +743,10 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
DiagnosticsNode treeDump; DiagnosticsNode treeDump;
try { try {
treeDump = renderViewElement?.toDiagnosticsNode() ?? DiagnosticsNode.message('<no tree>'); treeDump = renderViewElement?.toDiagnosticsNode() ?? DiagnosticsNode.message('<no tree>');
// TODO(jacobr): this is a hack to make sure the tree can safely be fully dumped. // We try to stringify the tree dump here (though we immediately discard the result) because
// Potentially everything is good enough without this case. // we want to make sure that if it can't be serialised, we replace it with a message that
// says the tree could not be serialised. Otherwise, the real exception might get obscured
// by side-effects of the underlying issues causing the tree dumping code to flail.
treeDump.toStringDeep(); treeDump.toStringDeep();
} catch (exception) { } catch (exception) {
treeDump = DiagnosticsNode.message('<additional error caught while dumping tree: $exception>', level: DiagnosticLevel.error); treeDump = DiagnosticsNode.message('<additional error caught while dumping tree: $exception>', level: DiagnosticLevel.error);
......
include: ../../analysis_options.yaml
linter:
rules:
# Tests try to catch errors all the time, so we don't worry about these lints for tests:
avoid_catches_without_on_clauses: false
avoid_catching_errors: false
...@@ -3,6 +3,7 @@ include: ../analysis_options.yaml ...@@ -3,6 +3,7 @@ include: ../analysis_options.yaml
linter: linter:
rules: rules:
avoid_catches_without_on_clauses: true avoid_catches_without_on_clauses: true
avoid_catching_errors: false # TODO(ianh): we should refactor the tool codebase to avoid relying on this so much
curly_braces_in_flow_control_structures: true curly_braces_in_flow_control_structures: true
library_private_types_in_public_api: false # Tool does not have any public API. library_private_types_in_public_api: false # Tool does not have any public API.
no_runtimeType_toString: false # We use runtimeType for debugging in the tool. no_runtimeType_toString: false # We use runtimeType for debugging in the tool.
......
...@@ -70,12 +70,11 @@ Future<int> run( ...@@ -70,12 +70,11 @@ Future<int> run(
// We already hit some error, so don't return success. The error path // We already hit some error, so don't return success. The error path
// (which should be in progress) is responsible for calling _exit(). // (which should be in progress) is responsible for calling _exit().
return 1; return 1;
// This catches all exceptions to send to crash logging, etc. } catch (error, stackTrace) { // ignore: avoid_catches_without_on_clauses
} catch (error, stackTrace) { // ignore: avoid_catches_without_on_clauses // This catches all exceptions to send to crash logging, etc.
firstError = error; firstError = error;
firstStackTrace = stackTrace; firstStackTrace = stackTrace;
return _handleToolError( return _handleToolError(error, stackTrace, verbose, args, reportCrashes, getVersion);
error, stackTrace, verbose, args, reportCrashes, getVersion);
} }
}, onError: (Object error, StackTrace stackTrace) async { // ignore: deprecated_member_use }, onError: (Object error, StackTrace stackTrace) async { // ignore: deprecated_member_use
// If sending a crash report throws an error into the zone, we don't want // If sending a crash report throws an error into the zone, we don't want
...@@ -164,7 +163,8 @@ Future<int> _handleToolError( ...@@ -164,7 +163,8 @@ Future<int> _handleToolError(
} catch (error) { // ignore: avoid_catches_without_on_clauses } catch (error) { // ignore: avoid_catches_without_on_clauses
globals.stdio.stderrWrite( globals.stdio.stderrWrite(
'Unable to generate crash report due to secondary error: $error\n' 'Unable to generate crash report due to secondary error: $error\n'
'${globals.userMessages.flutterToolBugInstructions}\n'); '${globals.userMessages.flutterToolBugInstructions}\n',
);
// Any exception thrown here (including one thrown by `_exit()`) will // Any exception thrown here (including one thrown by `_exit()`) will
// get caught by our zone's `onError` handler. In order to avoid an // get caught by our zone's `onError` handler. In order to avoid an
// infinite error loop, we throw an error that is recognized above // infinite error loop, we throw an error that is recognized above
......
...@@ -114,7 +114,7 @@ Future<T> asyncGuard<T>( ...@@ -114,7 +114,7 @@ Future<T> asyncGuard<T>(
} }
// This catches all exceptions so that they can be propagated to the // This catches all exceptions so that they can be propagated to the
// caller-supplied error handling or the completer. // caller-supplied error handling or the completer.
} catch (e, s) { // ignore: avoid_catches_without_on_clauses } catch (e, s) { // ignore: avoid_catches_without_on_clauses, forwards to Future
handleError(e, s); handleError(e, s);
} }
}, onError: (Object e, StackTrace s) { // ignore: deprecated_member_use }, onError: (Object e, StackTrace s) { // ignore: deprecated_member_use
......
...@@ -348,7 +348,7 @@ class ErrorHandlingFile ...@@ -348,7 +348,7 @@ class ErrorHandlingFile
sink.writeFromSync(buffer, 0, chunkLength); sink.writeFromSync(buffer, 0, chunkLength);
bytes += chunkLength; bytes += chunkLength;
} }
} catch (err) { // ignore: avoid_catches_without_on_clauses } catch (err) { // ignore: avoid_catches_without_on_clauses, rethrows
ErrorHandlingFileSystem.deleteIfExists(resultFile, recursive: true); ErrorHandlingFileSystem.deleteIfExists(resultFile, recursive: true);
rethrow; rethrow;
} finally { } finally {
......
...@@ -89,7 +89,7 @@ class _TaskQueueItem<T> { ...@@ -89,7 +89,7 @@ class _TaskQueueItem<T> {
Future<void> run() async { Future<void> run() async {
try { try {
_completer.complete(await _closure()); _completer.complete(await _closure());
} catch (e) { // ignore: avoid_catches_without_on_clauses } catch (e) { // ignore: avoid_catches_without_on_clauses, forwards to Future
_completer.completeError(e); _completer.completeError(e);
} finally { } finally {
onComplete?.call(); onComplete?.call();
......
...@@ -11,7 +11,7 @@ final AnchorElement _urlParsingNode = AnchorElement(); ...@@ -11,7 +11,7 @@ final AnchorElement _urlParsingNode = AnchorElement();
/// Example: for the url `http://example.com/foo`, the extracted pathname will /// Example: for the url `http://example.com/foo`, the extracted pathname will
/// be `/foo`. /// be `/foo`.
String extractPathname(String url) { String extractPathname(String url) {
_urlParsingNode.href = url; _urlParsingNode.href = url; // ignore: unsafe_html, node is never exposed to the user
final String pathname = _urlParsingNode.pathname ?? ''; final String pathname = _urlParsingNode.pathname ?? '';
return (pathname.isEmpty || pathname[0] == '/') ? pathname : '/$pathname'; return (pathname.isEmpty || pathname[0] == '/') ? pathname : '/$pathname';
} }
......
...@@ -54,6 +54,8 @@ Future<vms.VmService> _waitAndConnect( ...@@ -54,6 +54,8 @@ Future<vms.VmService> _waitAndConnect(
await service.getVersion(); await service.getVersion();
return service; return service;
} catch (e) { } catch (e) {
// We should not be catching all errors arbitrarily here, this might hide real errors.
// TODO(ianh): Determine which exceptions to catch here.
await socket.close(); await socket.close();
if (attempts > 5) { if (attempts > 5) {
_log.warning('It is taking an unusually long time to connect to the VM...'); _log.warning('It is taking an unusually long time to connect to the VM...');
......
...@@ -679,14 +679,13 @@ class _SshPortForwarder implements PortForwarder { ...@@ -679,14 +679,13 @@ class _SshPortForwarder implements PortForwarder {
/// If successful returns a valid [ServerSocket] (which must be disconnected /// If successful returns a valid [ServerSocket] (which must be disconnected
/// later). /// later).
static Future<ServerSocket?> _createLocalSocket() async { static Future<ServerSocket?> _createLocalSocket() async {
ServerSocket s;
try { try {
s = await ServerSocket.bind(_ipv4Loopback, 0); return await ServerSocket.bind(_ipv4Loopback, 0);
} catch (e) { } catch (e) {
// Failures are signaled by a return value of 0 from this function. // We should not be catching all errors arbitrarily here, this might hide real errors.
// TODO(ianh): Determine which exceptions to catch here.
_log.warning('_createLocalSocket failed: $e'); _log.warning('_createLocalSocket failed: $e');
return null; return null;
} }
return s;
} }
} }
...@@ -65,8 +65,7 @@ class WebCallbackManager implements CallbackManager { ...@@ -65,8 +65,7 @@ class WebCallbackManager implements CallbackManager {
'driver side'); 'driver side');
} }
} catch (exception) { } catch (exception) {
throw Exception('Web Driver Command failed: ${command.type} with ' throw Exception('Web Driver Command failed: ${command.type} with exception $exception');
'exception $exception');
} finally { } finally {
// Reset the completer. // Reset the completer.
_driverCommandComplete = Completer<bool>(); _driverCommandComplete = Completer<bool>();
......
...@@ -16,10 +16,8 @@ import 'dart:js_util' as js_util; ...@@ -16,10 +16,8 @@ import 'dart:js_util' as js_util;
/// See also: /// See also:
/// ///
/// * `_extension_io.dart`, which has the dart:io implementation /// * `_extension_io.dart`, which has the dart:io implementation
void registerWebServiceExtension( void registerWebServiceExtension(Future<Map<String, dynamic>> Function(Map<String, String>) callback) {
Future<Map<String, dynamic>> Function(Map<String, String>) callback) { js_util.setProperty(html.window, r'$flutterDriver', allowInterop((dynamic message) async {
js_util.setProperty(html.window, r'$flutterDriver',
allowInterop((dynamic message) async {
try { try {
final Map<String, dynamic> messageJson = jsonDecode(message as String) as Map<String, dynamic>; final Map<String, dynamic> messageJson = jsonDecode(message as String) as Map<String, dynamic>;
final Map<String, String> params = messageJson.cast<String, String>(); final Map<String, String> params = messageJson.cast<String, String>();
...@@ -27,9 +25,7 @@ void registerWebServiceExtension( ...@@ -27,9 +25,7 @@ void registerWebServiceExtension(
context[r'$flutterDriverResult'] = json.encode(result); context[r'$flutterDriverResult'] = json.encode(result);
} catch (error, stackTrace) { } catch (error, stackTrace) {
// Encode the error in the same format the FlutterDriver extension uses. // Encode the error in the same format the FlutterDriver extension uses.
// // See //packages/flutter_driver/lib/src/extension/extension.dart
// See:
// * packages\flutter_driver\lib\src\extension\extension.dart
context[r'$flutterDriverResult'] = json.encode(<String, dynamic>{ context[r'$flutterDriverResult'] = json.encode(<String, dynamic>{
'isError': true, 'isError': true,
'response': '$error\n$stackTrace', 'response': '$error\n$stackTrace',
......
...@@ -106,8 +106,10 @@ Future<void> integrationDriver( ...@@ -106,8 +106,10 @@ Future<void> integrationDriver(
try { try {
ok = await onScreenshot(screenshotName, screenshotBytes.cast<int>()); ok = await onScreenshot(screenshotName, screenshotBytes.cast<int>());
} catch (exception) { } catch (exception) {
throw StateError('Screenshot failure:\n' throw StateError(
'onScreenshot("$screenshotName", <bytes>) threw an exception: $exception'); 'Screenshot failure:\n'
'onScreenshot("$screenshotName", <bytes>) threw an exception: $exception',
);
} }
if (!ok) { if (!ok) {
failures.add(screenshotName); failures.add(screenshotName);
......
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