mirror of
https://github.com/flutter/flutter
synced 2024-09-29 21:14:10 +00:00
Enable more lints (#91642)
This commit is contained in:
parent
9570d353b3
commit
299d484903
|
@ -56,10 +56,10 @@ linter:
|
|||
- annotate_overrides
|
||||
# - avoid_annotating_with_dynamic # conflicts with always_specify_types
|
||||
- avoid_bool_literals_in_conditional_expressions
|
||||
# - avoid_catches_without_on_clauses # we do this commonly
|
||||
# - avoid_catching_errors # we do this commonly
|
||||
# - avoid_catches_without_on_clauses # blocked on https://github.com/dart-lang/linter/issues/3023
|
||||
# - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023
|
||||
- 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_empty_else
|
||||
- avoid_equals_and_hash_code_on_mutable_classes
|
||||
|
@ -68,7 +68,7 @@ linter:
|
|||
- avoid_function_literals_in_foreach_calls
|
||||
- avoid_implementing_value_types
|
||||
- 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_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
|
||||
|
@ -81,7 +81,7 @@ linter:
|
|||
# - 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_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_shadowing_type_parameters
|
||||
- avoid_single_cascade_in_expression_statements
|
||||
|
@ -201,7 +201,7 @@ linter:
|
|||
- tighten_type_of_initializing_formals
|
||||
# - type_annotate_public_apis # subset of always_specify_types
|
||||
- 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_brace_in_string_interps
|
||||
- unnecessary_const
|
||||
|
@ -216,24 +216,24 @@ linter:
|
|||
- unnecessary_nullable_for_final_variable_declarations
|
||||
- unnecessary_overrides
|
||||
- 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_string_escapes
|
||||
- unnecessary_string_interpolations
|
||||
- unnecessary_this
|
||||
- unrelated_type_equality_checks
|
||||
# - unsafe_html # not yet tested
|
||||
- unsafe_html
|
||||
- use_build_context_synchronously
|
||||
- use_full_hex_values_for_flutter_colors
|
||||
- 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_key_in_widget_constructors
|
||||
- use_late_for_private_fields_and_variables
|
||||
- use_named_constants
|
||||
- use_raw_strings
|
||||
- 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_test_throws_matchers
|
||||
# - 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
|
|||
|
||||
linter:
|
||||
rules:
|
||||
avoid_print: false # We use prints as debugging tools here all the time.
|
||||
only_throw_errors: false # Tests use a less... rigorous style.
|
||||
avoid_print: false # We use prints as debugging tools here a lot.
|
||||
|
||||
# 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
|
||||
|
|
5
dev/bots/analysis_options.yaml
Normal file
5
dev/bots/analysis_options.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
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 {
|
|||
final List<dynamic> result = decoder.convert(_data) as List<dynamic>;
|
||||
final int n = result.length;
|
||||
onResultListener('Decoded $n results');
|
||||
} catch (e, stack) {
|
||||
} on FormatException catch (e, stack) {
|
||||
debugPrint('Invalid JSON file: $e');
|
||||
debugPrint('$stack');
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import 'bitfield.dart' as bitfield;
|
||||
|
||||
/// 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].
|
||||
class BitField<T extends dynamic> implements bitfield.BitField<T> {
|
||||
|
|
|
@ -597,34 +597,27 @@ abstract class BindingBase {
|
|||
return Future<void>.delayed(Duration.zero);
|
||||
});
|
||||
|
||||
Object? caughtException;
|
||||
StackTrace? caughtStack;
|
||||
late Map<String, dynamic> result;
|
||||
try {
|
||||
result = await callback(parameters);
|
||||
} 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(
|
||||
exception: caughtException,
|
||||
stack: caughtStack,
|
||||
exception: exception,
|
||||
stack: stack,
|
||||
context: ErrorDescription('during a service extension callback for "$method"'),
|
||||
));
|
||||
return developer.ServiceExtensionResponse.error(
|
||||
developer.ServiceExtensionResponse.extensionError,
|
||||
json.encode(<String, String>{
|
||||
'exception': caughtException.toString(),
|
||||
'stack': caughtStack.toString(),
|
||||
'exception': exception.toString(),
|
||||
'stack': stack.toString(),
|
||||
'method': method,
|
||||
}),
|
||||
);
|
||||
}
|
||||
result['type'] = '_extensionType';
|
||||
result['method'] = method;
|
||||
return developer.ServiceExtensionResponse.result(json.encode(result));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -2832,6 +2832,8 @@ class DiagnosticsProperty<T> extends DiagnosticsNode {
|
|||
try {
|
||||
_value = _computeValue!();
|
||||
} catch (exception) {
|
||||
// The error is reported to inspector; rethrowing would destroy the
|
||||
// debugging experience.
|
||||
_exception = exception;
|
||||
_value = null;
|
||||
}
|
||||
|
|
|
@ -1091,6 +1091,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
|
|||
/// 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.
|
||||
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
|
||||
void setPromptRectRange(TextRange? newRange) {
|
||||
_autocorrectHighlightPainter.highlightedRange = newRange;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,9 @@ class RenderErrorBox extends RenderBox {
|
|||
_paragraph = null;
|
||||
}
|
||||
} 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 {
|
|||
}
|
||||
context.canvas.drawParagraph(_paragraph!, offset + Offset(left, top));
|
||||
}
|
||||
} catch (e) {
|
||||
// Intentionally left empty.
|
||||
} catch (error) {
|
||||
// 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
|
|||
}
|
||||
|
||||
/// Update the last known ScrollDirection when scrolling began.
|
||||
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
|
||||
void updateScrollStartDirection(ScrollDirection direction) {
|
||||
_lastStartedScrollDirection = direction;
|
||||
}
|
||||
|
|
|
@ -319,6 +319,7 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
|
|||
///
|
||||
/// * [SystemChrome.setEnabledSystemUIMode], which specifies the
|
||||
/// [SystemUiMode] to have visible when the application is running.
|
||||
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
|
||||
void setSystemUiChangeCallback(SystemUiChangeCallback? callback) {
|
||||
_systemUiChangeCallback = callback;
|
||||
}
|
||||
|
@ -387,7 +388,6 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
|
|||
try {
|
||||
response = await handler(data);
|
||||
} catch (exception, stack) {
|
||||
|
||||
FlutterError.reportError(FlutterErrorDetails(
|
||||
exception: exception,
|
||||
stack: stack,
|
||||
|
|
|
@ -376,7 +376,7 @@ class StandardMessageCodec implements MessageCodec<Object?> {
|
|||
// decoding because we use tags to detect the type of value.
|
||||
buffer.putUint8(_valueFloat64);
|
||||
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) {
|
||||
buffer.putUint8(_valueInt32);
|
||||
buffer.putInt32(value);
|
||||
|
|
|
@ -410,8 +410,8 @@ class MethodChannel {
|
|||
);
|
||||
} on MissingPluginException {
|
||||
return null;
|
||||
} catch (e) {
|
||||
return codec.encodeErrorEnvelope(code: 'error', message: e.toString());
|
||||
} catch (error) {
|
||||
return codec.encodeErrorEnvelope(code: 'error', message: error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1006,7 +1006,9 @@ bool debugIsSerializableForRestoration(Object? object) {
|
|||
try {
|
||||
const StandardMessageCodec().encodeMessage(object);
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -160,6 +160,7 @@ abstract class Action<T extends Intent> with Diagnosticable {
|
|||
final ObserverList<ActionListenerCallback> _listeners = ObserverList<ActionListenerCallback>();
|
||||
|
||||
Action<T>? _currentCallingAction;
|
||||
// ignore: use_setters_to_change_properties, (code predates enabling of this lint)
|
||||
void _updateCallingAction(Action<T>? value) {
|
||||
_currentCallingAction = value;
|
||||
}
|
||||
|
|
|
@ -2342,6 +2342,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
|||
}
|
||||
|
||||
Rect? _currentCaretRect;
|
||||
// ignore: use_setters_to_change_properties, (this is used as a callback, can't be a setter)
|
||||
void _handleCaretChanged(Rect caretRect) {
|
||||
_currentCaretRect = caretRect;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
/// `setState` is called.
|
||||
@protected
|
||||
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
|
||||
void setValue(T? value) {
|
||||
_value = value;
|
||||
}
|
||||
|
|
|
@ -4453,8 +4453,10 @@ class ErrorWidget extends LeafRenderObjectWidget {
|
|||
static String _stringify(Object? exception) {
|
||||
try {
|
||||
return exception.toString();
|
||||
} catch (e) {
|
||||
// intentionally left empty.
|
||||
} catch (error) {
|
||||
// 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';
|
||||
}
|
||||
|
@ -5426,6 +5428,9 @@ abstract class RenderObjectElement extends Element {
|
|||
if (badAncestors.isNotEmpty) {
|
||||
badAncestors.insert(0, result);
|
||||
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>[
|
||||
ErrorSummary('Incorrect use of ParentDataWidget.'),
|
||||
ErrorDescription('The following ParentDataWidgets are providing parent data to the same RenderObject:'),
|
||||
|
@ -5763,9 +5768,10 @@ abstract class RenderObjectElement extends Element {
|
|||
]);
|
||||
}
|
||||
} on FlutterError catch (e) {
|
||||
// Catching the exception directly to avoid activating the ErrorWidget.
|
||||
// Since the tree is in a broken state, adding the ErrorWidget would
|
||||
// cause more exceptions.
|
||||
// We catch the exception directly to avoid activating the ErrorWidget,
|
||||
// while still allowing debuggers to break on exception. Since the tree
|
||||
// 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);
|
||||
}
|
||||
return true;
|
||||
|
@ -6036,6 +6042,7 @@ abstract class RootRenderObjectElement extends RenderObjectElement {
|
|||
/// to [runApp]. The binding is responsible for driving the build pipeline by
|
||||
/// calling the build owner's [BuildOwner.buildScope] method. See
|
||||
/// [WidgetsBinding.drawFrame].
|
||||
// ignore: use_setters_to_change_properties, (API predates enforcing the lint)
|
||||
void assignOwner(BuildOwner owner) {
|
||||
_owner = owner;
|
||||
}
|
||||
|
|
|
@ -175,6 +175,7 @@ abstract class Route<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// ignore: use_setters_to_change_properties, (setters can't be private)
|
||||
void _updateRestorationId(String? restorationId) {
|
||||
_restorationScopeId.value = restorationId;
|
||||
}
|
||||
|
|
|
@ -320,6 +320,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
|
|||
/// middle of layout and applying the new position immediately.
|
||||
/// * [animateTo], which is like [jumpTo] but animating to the
|
||||
/// destination offset.
|
||||
// ignore: use_setters_to_change_properties, (API is intended to discourage setting value)
|
||||
void correctPixels(double value) {
|
||||
_pixels = value;
|
||||
}
|
||||
|
|
|
@ -1277,7 +1277,10 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
|||
assert (() {
|
||||
try {
|
||||
scrollController!.position;
|
||||
} catch (_) {
|
||||
} catch (error) {
|
||||
if (scrollController == null || scrollController.positions.length <= 1) {
|
||||
rethrow;
|
||||
}
|
||||
throw FlutterError.fromParts(<DiagnosticsNode>[
|
||||
ErrorSummary(
|
||||
'The $controllerForError is currently attached to more than one '
|
||||
|
|
|
@ -204,6 +204,7 @@ abstract class SliverChildDelegate {
|
|||
if (children != null)
|
||||
description.add('estimated child count: $children');
|
||||
} catch (e) {
|
||||
// The exception is forwarded to widget inspector.
|
||||
description.add('estimated child count: EXCEPTION (${e.runtimeType})');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1587,7 +1587,13 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget
|
|||
final bool hasStrings;
|
||||
try {
|
||||
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
|
||||
// unknown so that it will try to update again later.
|
||||
if (_disposed || value == ClipboardStatus.unknown) {
|
||||
|
|
|
@ -1962,6 +1962,8 @@ mixin WidgetInspectorService {
|
|||
FlutterErrorDetails(
|
||||
exception: exception,
|
||||
stack: stack,
|
||||
library: 'widget inspector library',
|
||||
context: ErrorDescription('while tracking widget repaints'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,4 +2,8 @@ include: ../analysis_options.yaml
|
|||
|
||||
linter:
|
||||
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() {
|
|||
checkEncodeDecode<dynamic>(json, -9223372036854775807);
|
||||
});
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
@ -72,7 +72,7 @@ void main() {
|
|||
});
|
||||
test('should encode and decode a list containing big numbers', () {
|
||||
final List<dynamic> message = <dynamic>[
|
||||
-7000000000000000007,
|
||||
-7000000000000000007, // ignore: avoid_js_rounded_ints, browsers are skipped below
|
||||
Int64List.fromList(<int>[-0x7fffffffffffffff - 1, 0, 0x7fffffffffffffff]),
|
||||
];
|
||||
checkEncodeDecode<dynamic>(standard, message);
|
||||
|
|
|
@ -564,6 +564,8 @@ Future<vms.VmService> _waitAndConnect(String url, Map<String, dynamic>? headers)
|
|||
await service.getVersion();
|
||||
return service;
|
||||
} 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();
|
||||
if (attempts > 5) {
|
||||
_log('It is taking an unusually long time to connect to the VM...');
|
||||
|
|
|
@ -115,9 +115,10 @@ class WebFlutterDriver extends FlutterDriver {
|
|||
response = data != null ? (json.decode(data as String) as Map<String, dynamic>?)! : <String, dynamic>{};
|
||||
_logCommunication('<<< $response');
|
||||
} catch (error, stackTrace) {
|
||||
throw DriverError("Failed to respond to $command due to remote error\n : \$flutterDriver('${jsonEncode(serialized)}')",
|
||||
error,
|
||||
stackTrace
|
||||
throw DriverError(
|
||||
"Failed to respond to $command due to remote error\n : \$flutterDriver('${jsonEncode(serialized)}')",
|
||||
error,
|
||||
stackTrace
|
||||
);
|
||||
}
|
||||
if (response['isError'] == true)
|
||||
|
@ -261,8 +262,10 @@ class FlutterWebConnection {
|
|||
dynamic result;
|
||||
try {
|
||||
await _driver.execute(script, <void>[]);
|
||||
} catch (_) {
|
||||
// In case there is an exception, do nothing
|
||||
} 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.
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -271,7 +274,10 @@ class FlutterWebConnection {
|
|||
matcher: isNotNull,
|
||||
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.
|
||||
return null;
|
||||
} finally {
|
||||
|
|
|
@ -329,15 +329,9 @@ class SkiaGoldClient {
|
|||
final Uri requestForImage = Uri.parse(
|
||||
'https://flutter-gold.skia.org/img/images/$imageHash.png',
|
||||
);
|
||||
|
||||
try {
|
||||
final io.HttpClientRequest request = await httpClient.getUrl(requestForImage);
|
||||
final io.HttpClientResponse response = await request.close();
|
||||
await response.forEach((List<int> bytes) => imageBytes.addAll(bytes));
|
||||
|
||||
} catch(e) {
|
||||
rethrow;
|
||||
}
|
||||
final io.HttpClientRequest request = await httpClient.getUrl(requestForImage);
|
||||
final io.HttpClientResponse response = await request.close();
|
||||
await response.forEach((List<int> bytes) => imageBytes.addAll(bytes));
|
||||
},
|
||||
SkiaGoldHttpOverrides(),
|
||||
);
|
||||
|
|
|
@ -743,8 +743,10 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
|||
DiagnosticsNode treeDump;
|
||||
try {
|
||||
treeDump = renderViewElement?.toDiagnosticsNode() ?? DiagnosticsNode.message('<no tree>');
|
||||
// TODO(jacobr): this is a hack to make sure the tree can safely be fully dumped.
|
||||
// Potentially everything is good enough without this case.
|
||||
// We try to stringify the tree dump here (though we immediately discard the result) because
|
||||
// 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();
|
||||
} catch (exception) {
|
||||
treeDump = DiagnosticsNode.message('<additional error caught while dumping tree: $exception>', level: DiagnosticLevel.error);
|
||||
|
|
7
packages/flutter_test/test/analysis_options.yaml
Normal file
7
packages/flutter_test/test/analysis_options.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
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
|
|||
linter:
|
||||
rules:
|
||||
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
|
||||
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.
|
||||
|
|
|
@ -70,12 +70,11 @@ Future<int> run(
|
|||
// We already hit some error, so don't return success. The error path
|
||||
// (which should be in progress) is responsible for calling _exit().
|
||||
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;
|
||||
firstStackTrace = stackTrace;
|
||||
return _handleToolError(
|
||||
error, stackTrace, verbose, args, reportCrashes, getVersion);
|
||||
return _handleToolError(error, stackTrace, verbose, args, reportCrashes, getVersion);
|
||||
}
|
||||
}, 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
|
||||
|
@ -164,7 +163,8 @@ Future<int> _handleToolError(
|
|||
} catch (error) { // ignore: avoid_catches_without_on_clauses
|
||||
globals.stdio.stderrWrite(
|
||||
'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
|
||||
// get caught by our zone's `onError` handler. In order to avoid an
|
||||
// infinite error loop, we throw an error that is recognized above
|
||||
|
|
|
@ -114,7 +114,7 @@ Future<T> asyncGuard<T>(
|
|||
}
|
||||
// This catches all exceptions so that they can be propagated to the
|
||||
// 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);
|
||||
}
|
||||
}, onError: (Object e, StackTrace s) { // ignore: deprecated_member_use
|
||||
|
|
|
@ -348,7 +348,7 @@ class ErrorHandlingFile
|
|||
sink.writeFromSync(buffer, 0, 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);
|
||||
rethrow;
|
||||
} finally {
|
||||
|
|
|
@ -89,7 +89,7 @@ class _TaskQueueItem<T> {
|
|||
Future<void> run() async {
|
||||
try {
|
||||
_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);
|
||||
} finally {
|
||||
onComplete?.call();
|
||||
|
|
|
@ -11,7 +11,7 @@ final AnchorElement _urlParsingNode = AnchorElement();
|
|||
/// Example: for the url `http://example.com/foo`, the extracted pathname will
|
||||
/// be `/foo`.
|
||||
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 ?? '';
|
||||
return (pathname.isEmpty || pathname[0] == '/') ? pathname : '/$pathname';
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@ Future<vms.VmService> _waitAndConnect(
|
|||
await service.getVersion();
|
||||
return service;
|
||||
} 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();
|
||||
if (attempts > 5) {
|
||||
_log.warning('It is taking an unusually long time to connect to the VM...');
|
||||
|
|
|
@ -679,14 +679,13 @@ class _SshPortForwarder implements PortForwarder {
|
|||
/// If successful returns a valid [ServerSocket] (which must be disconnected
|
||||
/// later).
|
||||
static Future<ServerSocket?> _createLocalSocket() async {
|
||||
ServerSocket s;
|
||||
try {
|
||||
s = await ServerSocket.bind(_ipv4Loopback, 0);
|
||||
return await ServerSocket.bind(_ipv4Loopback, 0);
|
||||
} 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');
|
||||
return null;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,8 +65,7 @@ class WebCallbackManager implements CallbackManager {
|
|||
'driver side');
|
||||
}
|
||||
} catch (exception) {
|
||||
throw Exception('Web Driver Command failed: ${command.type} with '
|
||||
'exception $exception');
|
||||
throw Exception('Web Driver Command failed: ${command.type} with exception $exception');
|
||||
} finally {
|
||||
// Reset the completer.
|
||||
_driverCommandComplete = Completer<bool>();
|
||||
|
|
|
@ -16,10 +16,8 @@ import 'dart:js_util' as js_util;
|
|||
/// See also:
|
||||
///
|
||||
/// * `_extension_io.dart`, which has the dart:io implementation
|
||||
void registerWebServiceExtension(
|
||||
Future<Map<String, dynamic>> Function(Map<String, String>) callback) {
|
||||
js_util.setProperty(html.window, r'$flutterDriver',
|
||||
allowInterop((dynamic message) async {
|
||||
void registerWebServiceExtension(Future<Map<String, dynamic>> Function(Map<String, String>) callback) {
|
||||
js_util.setProperty(html.window, r'$flutterDriver', allowInterop((dynamic message) async {
|
||||
try {
|
||||
final Map<String, dynamic> messageJson = jsonDecode(message as String) as Map<String, dynamic>;
|
||||
final Map<String, String> params = messageJson.cast<String, String>();
|
||||
|
@ -27,9 +25,7 @@ void registerWebServiceExtension(
|
|||
context[r'$flutterDriverResult'] = json.encode(result);
|
||||
} catch (error, stackTrace) {
|
||||
// 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>{
|
||||
'isError': true,
|
||||
'response': '$error\n$stackTrace',
|
||||
|
|
|
@ -106,8 +106,10 @@ Future<void> integrationDriver(
|
|||
try {
|
||||
ok = await onScreenshot(screenshotName, screenshotBytes.cast<int>());
|
||||
} catch (exception) {
|
||||
throw StateError('Screenshot failure:\n'
|
||||
'onScreenshot("$screenshotName", <bytes>) threw an exception: $exception');
|
||||
throw StateError(
|
||||
'Screenshot failure:\n'
|
||||
'onScreenshot("$screenshotName", <bytes>) threw an exception: $exception',
|
||||
);
|
||||
}
|
||||
if (!ok) {
|
||||
failures.add(screenshotName);
|
||||
|
|
Loading…
Reference in a new issue