diff --git a/analysis_options.yaml b/analysis_options.yaml index 519b1d8cb8..bfeeffe90f 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -61,7 +61,7 @@ linter: # - avoid_catching_errors # we do this commonly - avoid_classes_with_only_static_members # - avoid_double_and_int_checks # only useful when targeting JS runtime - # - avoid_dynamic_calls # not yet tested + - avoid_dynamic_calls - avoid_empty_else - avoid_equals_and_hash_code_on_mutable_classes - avoid_escaping_inner_quotes diff --git a/dev/bots/prepare_package.dart b/dev/bots/prepare_package.dart index 7f5b498509..4c88c793f9 100644 --- a/dev/bots/prepare_package.dart +++ b/dev/bots/prepare_package.dart @@ -595,7 +595,7 @@ class ArchivePublisher { if (!jsonData.containsKey('current_release')) { jsonData['current_release'] = {}; } - jsonData['current_release'][branchName] = revision; + (jsonData['current_release'] as Map)[branchName] = revision; if (!jsonData.containsKey('releases')) { jsonData['releases'] = >[]; } diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 49248d6933..da70f28700 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -1059,7 +1059,7 @@ Future _ensureChromeDriverIsRunning() async { final HttpClientResponse response = await request.close(); final Map webDriverStatus = json.decode(await response.transform(utf8.decoder).join('')) as Map; client.close(); - final bool webDriverReady = webDriverStatus['value']['ready'] as bool; + final bool webDriverReady = (webDriverStatus['value'] as Map)['ready'] as bool; if (!webDriverReady) { throw Exception('WebDriver not available.'); } diff --git a/dev/bots/test/prepare_package_test.dart b/dev/bots/test/prepare_package_test.dart index b8937b0fc3..509d0f9f92 100644 --- a/dev/bots/test/prepare_package_test.dart +++ b/dev/bots/test/prepare_package_test.dart @@ -394,7 +394,7 @@ void main() { // Make sure the new entry is first (and hopefully it takes less than a // minute to go from publishArchive above to this line!). expect( - DateTime.now().difference(DateTime.parse(releases[0]['release_date'] as String)), + DateTime.now().difference(DateTime.parse((releases[0] as Map)['release_date'] as String)), lessThan(const Duration(minutes: 1)), ); const JsonEncoder encoder = JsonEncoder.withIndent(' '); diff --git a/dev/bots/unpublish_package.dart b/dev/bots/unpublish_package.dart index 799211d8ff..dfe9d6edd4 100644 --- a/dev/bots/unpublish_package.dart +++ b/dev/bots/unpublish_package.dart @@ -255,7 +255,7 @@ class ArchiveUnpublisher { }); jsonData['releases'] = releases; for (final Channel channel in channels) { - if (!revisionsBeingRemoved.contains(jsonData['current_release'][getChannelName(channel)])) { + if (!revisionsBeingRemoved.contains((jsonData['current_release'] as Map)[getChannelName(channel)])) { // Don't replace the current release if it's not one of the revisions we're removing. continue; } @@ -263,7 +263,7 @@ class ArchiveUnpublisher { if (replacementRelease == null) { throw UnpublishException('Unable to find previous release for channel ${getChannelName(channel)}.'); } - jsonData['current_release'][getChannelName(channel)] = replacementRelease['hash']; + (jsonData['current_release'] as Map)[getChannelName(channel)] = replacementRelease['hash']; print( '${confirmed ? 'Reverting' : 'Would revert'} current ${getChannelName(channel)} ' '${getPublishedPlatform(platform)} release to ${replacementRelease['hash']} (version ${replacementRelease['version']}).' diff --git a/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_with_semantics.dart b/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_with_semantics.dart index 434d0c7b37..7338d3dc0d 100644 --- a/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_with_semantics.dart +++ b/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_with_semantics.dart @@ -31,7 +31,7 @@ Future main() async { final Map data = {}; for (final String key in withSemantics.benchmarkScoreKeys) { final String deltaKey = 'delta_$key'; - data[deltaKey] = withSemantics.data[key] - withoutSemantics.data[key]; + data[deltaKey] = (withSemantics.data[key] as num) - (withoutSemantics.data[key] as num); data['semantics_$key'] = withSemantics.data[key]; data[key] = withoutSemantics.data[key]; benchmarkScoreKeys.add(deltaKey); diff --git a/dev/devicelab/lib/framework/browser.dart b/dev/devicelab/lib/framework/browser.dart index ec4c531766..9d2f544bec 100644 --- a/dev/devicelab/lib/framework/browser.dart +++ b/dev/devicelab/lib/framework/browser.dart @@ -273,7 +273,7 @@ Future _getRemoteDebuggerUrl(Uri base) async { if (jsonObject == null || jsonObject.isEmpty) { return base; } - return base.resolve(jsonObject.first['webSocketDebuggerUrl'] as String); + return base.resolve((jsonObject.first as Map)['webSocketDebuggerUrl'] as String); } /// Summarizes a Blink trace down to a few interesting values. diff --git a/dev/devicelab/lib/framework/manifest.dart b/dev/devicelab/lib/framework/manifest.dart index b14502a032..836c8ab3b2 100644 --- a/dev/devicelab/lib/framework/manifest.dart +++ b/dev/devicelab/lib/framework/manifest.dart @@ -104,11 +104,12 @@ Manifest _validateAndParseManifest(YamlMap manifestYaml) { List _validateAndParseTasks(dynamic tasksYaml) { _checkType(tasksYaml is YamlMap, tasksYaml, 'Value of "tasks"', 'dictionary'); - final List sortedKeys = (tasksYaml as YamlMap).keys.toList()..sort(); - return sortedKeys.map((dynamic taskName) => _validateAndParseTask(taskName, tasksYaml[taskName])).toList(); + final List sortedKeys = (tasksYaml as YamlMap).keys.toList().cast()..sort(); + // ignore: avoid_dynamic_calls + return sortedKeys.map((String taskName) => _validateAndParseTask(taskName, tasksYaml[taskName])).toList(); } -ManifestTask _validateAndParseTask(dynamic taskName, dynamic taskYaml) { +ManifestTask _validateAndParseTask(String taskName, dynamic taskYaml) { _checkType(taskName is String, taskName, 'Task name', 'string'); _checkType(taskYaml is YamlMap, taskYaml, 'Value of task "$taskName"', 'dictionary'); _checkKeys(taskYaml as YamlMap, 'Value of task "$taskName"', const [ @@ -119,27 +120,32 @@ ManifestTask _validateAndParseTask(dynamic taskName, dynamic taskYaml) { 'timeout_in_minutes', 'on_luci', ]); - + // ignore: avoid_dynamic_calls final dynamic isFlaky = taskYaml['flaky']; if (isFlaky != null) { _checkType(isFlaky is bool, isFlaky, 'flaky', 'boolean'); } + // ignore: avoid_dynamic_calls final dynamic timeoutInMinutes = taskYaml['timeout_in_minutes']; if (timeoutInMinutes != null) { _checkType(timeoutInMinutes is int, timeoutInMinutes, 'timeout_in_minutes', 'integer'); } - final List capabilities = _validateAndParseCapabilities(taskName as String, taskYaml['required_agent_capabilities']); + // ignore: avoid_dynamic_calls + final List capabilities = _validateAndParseCapabilities(taskName, taskYaml['required_agent_capabilities']); + // ignore: avoid_dynamic_calls final dynamic onLuci = taskYaml['on_luci']; if (onLuci != null) { _checkType(onLuci is bool, onLuci, 'on_luci', 'boolean'); } return ManifestTask._( - name: taskName as String, + name: taskName, + // ignore: avoid_dynamic_calls description: taskYaml['description'] as String, + // ignore: avoid_dynamic_calls stage: taskYaml['stage'] as String, requiredAgentCapabilities: capabilities as List, isFlaky: isFlaky as bool ?? false, @@ -150,8 +156,9 @@ ManifestTask _validateAndParseTask(dynamic taskName, dynamic taskYaml) { List _validateAndParseCapabilities(String taskName, dynamic capabilitiesYaml) { _checkType(capabilitiesYaml is List, capabilitiesYaml, 'required_agent_capabilities', 'list'); - for (int i = 0; i < (capabilitiesYaml as List).length; i++) { - final dynamic capability = capabilitiesYaml[i]; + final List capabilities = capabilitiesYaml as List; + for (int i = 0; i < capabilities.length; i++) { + final dynamic capability = capabilities[i]; _checkType(capability is String, capability, 'required_agent_capabilities[$i]', 'string'); } return (capabilitiesYaml as List).cast(); diff --git a/dev/devicelab/lib/framework/task_result.dart b/dev/devicelab/lib/framework/task_result.dart index ca1dc935bb..6d58ed03c7 100644 --- a/dev/devicelab/lib/framework/task_result.dart +++ b/dev/devicelab/lib/framework/task_result.dart @@ -31,7 +31,7 @@ class TaskResult { 'result data ${prettyJson.convert(data)}'; } else if (data[key] is! num) { throw 'Invalid benchmark score for key "$key". It is expected to be a num ' - 'but was ${data[key].runtimeType}: ${prettyJson.convert(data[key])}'; + 'but was ${(data[key] as Object).runtimeType}: ${prettyJson.convert(data[key])}'; } } } diff --git a/dev/devicelab/lib/tasks/hot_mode_tests.dart b/dev/devicelab/lib/tasks/hot_mode_tests.dart index 1e6b4b8f9e..ca9eb43e67 100644 --- a/dev/devicelab/lib/tasks/hot_mode_tests.dart +++ b/dev/devicelab/lib/tasks/hot_mode_tests.dart @@ -151,24 +151,43 @@ TaskFunction createHotModeTest({String deviceIdOverride, Map env return TaskResult.success( { + // ignore: avoid_dynamic_calls 'hotReloadInitialDevFSSyncMilliseconds': smallReloadData['hotReloadInitialDevFSSyncMilliseconds'][0], + // ignore: avoid_dynamic_calls 'hotRestartMillisecondsToFrame': smallReloadData['hotRestartMillisecondsToFrame'][0], + // ignore: avoid_dynamic_calls 'hotReloadMillisecondsToFrame' : smallReloadData['hotReloadMillisecondsToFrame'][0], + // ignore: avoid_dynamic_calls 'hotReloadDevFSSyncMilliseconds': smallReloadData['hotReloadDevFSSyncMilliseconds'][0], + // ignore: avoid_dynamic_calls 'hotReloadFlutterReassembleMilliseconds': smallReloadData['hotReloadFlutterReassembleMilliseconds'][0], + // ignore: avoid_dynamic_calls 'hotReloadVMReloadMilliseconds': smallReloadData['hotReloadVMReloadMilliseconds'][0], + // ignore: avoid_dynamic_calls 'hotReloadMillisecondsToFrameAfterChange' : smallReloadData['hotReloadMillisecondsToFrame'][1], + // ignore: avoid_dynamic_calls 'hotReloadDevFSSyncMillisecondsAfterChange': smallReloadData['hotReloadDevFSSyncMilliseconds'][1], + // ignore: avoid_dynamic_calls 'hotReloadFlutterReassembleMillisecondsAfterChange': smallReloadData['hotReloadFlutterReassembleMilliseconds'][1], + // ignore: avoid_dynamic_calls 'hotReloadVMReloadMillisecondsAfterChange': smallReloadData['hotReloadVMReloadMilliseconds'][1], + // ignore: avoid_dynamic_calls 'hotReloadInitialDevFSSyncAfterRelaunchMilliseconds' : freshRestartReloadsData['hotReloadInitialDevFSSyncMilliseconds'][0], + // ignore: avoid_dynamic_calls 'hotReloadMillisecondsToFrameAfterMediumChange' : mediumReloadData['hotReloadMillisecondsToFrame'][1], + // ignore: avoid_dynamic_calls 'hotReloadDevFSSyncMillisecondsAfterMediumChange': mediumReloadData['hotReloadDevFSSyncMilliseconds'][1], + // ignore: avoid_dynamic_calls 'hotReloadFlutterReassembleMillisecondsAfterMediumChange': mediumReloadData['hotReloadFlutterReassembleMilliseconds'][1], + // ignore: avoid_dynamic_calls 'hotReloadVMReloadMillisecondsAfterMediumChange': mediumReloadData['hotReloadVMReloadMilliseconds'][1], + // ignore: avoid_dynamic_calls 'hotReloadMillisecondsToFrameAfterLargeChange' : largeReloadData['hotReloadMillisecondsToFrame'][1], + // ignore: avoid_dynamic_calls 'hotReloadDevFSSyncMillisecondsAfterLargeChange': largeReloadData['hotReloadDevFSSyncMilliseconds'][1], + // ignore: avoid_dynamic_calls 'hotReloadFlutterReassembleMillisecondsAfterLargeChange': largeReloadData['hotReloadFlutterReassembleMilliseconds'][1], + // ignore: avoid_dynamic_calls 'hotReloadVMReloadMillisecondsAfterLargeChange': largeReloadData['hotReloadVMReloadMilliseconds'][1], }, benchmarkScoreKeys: [ diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index eacdba32ee..244ac841fd 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -421,13 +421,15 @@ TaskFunction createsScrollSmoothnessPerfTest() { final Map result = {}; void addResult(dynamic data, String suffix) { assert(data is Map); - const List metricKeys = [ - 'janky_count', - 'average_abs_jerk', - 'dropped_frame_count', - ]; - for (final String key in metricKeys) { - result[key+suffix] = data[key]; + if (data is Map) { + const List metricKeys = [ + 'janky_count', + 'average_abs_jerk', + 'dropped_frame_count', + ]; + for (final String key in metricKeys) { + result[key + suffix] = data[key]; + } } } addResult(data['resample on with 90Hz input'], '_with_resampler_90Hz'); @@ -1472,15 +1474,15 @@ class DevToolsMemoryTest { final Map data = json.decode( file('$project/$_kJsonFileName').readAsStringSync(), ) as Map; - final List samples = data['samples']['data'] as List; + final List> samples = (data['samples'] as Map)['data'] as List>; int maxRss = 0; int maxAdbTotal = 0; - for (final dynamic sample in samples) { + for (final Map sample in samples) { if (sample['rss'] != null) { maxRss = math.max(maxRss, sample['rss'] as int); } if (sample['adb_memoryInfo'] != null) { - maxAdbTotal = math.max(maxAdbTotal, sample['adb_memoryInfo']['Total'] as int); + maxAdbTotal = math.max(maxAdbTotal, (sample['adb_memoryInfo'] as Map)['Total'] as int); } } diff --git a/dev/devicelab/lib/tasks/web_benchmarks.dart b/dev/devicelab/lib/tasks/web_benchmarks.dart index 8eb05911da..77af15db3d 100644 --- a/dev/devicelab/lib/tasks/web_benchmarks.dart +++ b/dev/devicelab/lib/tasks/web_benchmarks.dart @@ -69,7 +69,7 @@ Future runWebBenchmark({ @required bool useCanvasKit }) async { final BlinkTraceSummary traceSummary = BlinkTraceSummary.fromJson(latestPerformanceTrace); profile['totalUiFrame.average'] = traceSummary.averageTotalUIFrameTime.inMicroseconds; profile['scoreKeys'] ??= []; // using dynamic for consistency with JSON - profile['scoreKeys'].add('totalUiFrame.average'); + (profile['scoreKeys'] as List).add('totalUiFrame.average'); latestPerformanceTrace = null; } collectedProfiles.add(profile); diff --git a/dev/integration_tests/flutter_gallery/lib/demo/transformations/transformations_demo_color_picker.dart b/dev/integration_tests/flutter_gallery/lib/demo/transformations/transformations_demo_color_picker.dart index 62c9126c3c..3440289b41 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/transformations/transformations_demo_color_picker.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/transformations/transformations_demo_color_picker.dart @@ -46,7 +46,7 @@ class _ColorPickerSwatch extends StatelessWidget { final Color color; final bool selected; - final Function? onTap; + final VoidCallback? onTap; @override Widget build (BuildContext context) { diff --git a/dev/integration_tests/flutter_gallery/test_driver/transitions_perf_test.dart b/dev/integration_tests/flutter_gallery/test_driver/transitions_perf_test.dart index 5d86c8079e..7e976580c1 100644 --- a/dev/integration_tests/flutter_gallery/test_driver/transitions_perf_test.dart +++ b/dev/integration_tests/flutter_gallery/test_driver/transitions_perf_test.dart @@ -42,7 +42,7 @@ Future saveDurationsHistogram(List> events, String ou frameStart = timestamp; } else { assert(phase == 'E'); - final String routeName = startEvent['args']['to'] as String; + final String routeName = (startEvent['args'] as Map)['to'] as String; durations[routeName] ??= []; durations[routeName]!.add(timestamp - frameStart!); startEvent = null; @@ -79,7 +79,7 @@ Future saveDurationsHistogram(List> events, String ou continue; final String routeName = eventName == 'Start Transition' - ? eventIter.current['args']['to'] as String + ? (eventIter.current['args'] as Map)['to'] as String : ''; if (eventName == lastEventName && routeName == lastRouteName) { diff --git a/dev/tools/gen_keycodes/lib/logical_key_data.dart b/dev/tools/gen_keycodes/lib/logical_key_data.dart index 96921d7830..3ff9cdaafa 100644 --- a/dev/tools/gen_keycodes/lib/logical_key_data.dart +++ b/dev/tools/gen_keycodes/lib/logical_key_data.dart @@ -440,18 +440,18 @@ class LogicalKeyEntry { LogicalKeyEntry.fromJsonMapEntry(Map map) : value = map['value'] as int, name = map['name'] as String, - webNames = _toNonEmptyArray(map['names']['web']), - macOSKeyCodeNames = _toNonEmptyArray(map['names']['macos']), - macOSKeyCodeValues = _toNonEmptyArray(map['values']?['macos']), - iOSKeyCodeNames = _toNonEmptyArray(map['names']['ios']), - iOSKeyCodeValues = _toNonEmptyArray(map['values']?['ios']), - gtkNames = _toNonEmptyArray(map['names']['gtk']), - gtkValues = _toNonEmptyArray(map['values']?['gtk']), - windowsNames = _toNonEmptyArray(map['names']['windows']), - windowsValues = _toNonEmptyArray(map['values']?['windows']), - androidNames = _toNonEmptyArray(map['names']['android']), - androidValues = _toNonEmptyArray(map['values']?['android']), - fuchsiaValues = _toNonEmptyArray(map['values']?['fuchsia']), + webNames = _toNonEmptyArray((map['names'] as Map)['web']), + macOSKeyCodeNames = _toNonEmptyArray((map['names'] as Map)['macos']), + macOSKeyCodeValues = _toNonEmptyArray((map['values'] as Map?)?['macos']), + iOSKeyCodeNames = _toNonEmptyArray((map['names'] as Map)['ios']), + iOSKeyCodeValues = _toNonEmptyArray((map['values'] as Map?)?['ios']), + gtkNames = _toNonEmptyArray((map['names'] as Map)['gtk']), + gtkValues = _toNonEmptyArray((map['values'] as Map?)?['gtk']), + windowsNames = _toNonEmptyArray((map['names'] as Map)['windows']), + windowsValues = _toNonEmptyArray((map['values'] as Map?)?['windows']), + androidNames = _toNonEmptyArray((map['names'] as Map)['android']), + androidValues = _toNonEmptyArray((map['values'] as Map?)?['android']), + fuchsiaValues = _toNonEmptyArray((map['values'] as Map?)?['fuchsia']), keyLabel = map['keyLabel'] as String?; final int value; diff --git a/dev/tools/gen_keycodes/lib/physical_key_data.dart b/dev/tools/gen_keycodes/lib/physical_key_data.dart index 3fefe84f81..b02cd76b82 100644 --- a/dev/tools/gen_keycodes/lib/physical_key_data.dart +++ b/dev/tools/gen_keycodes/lib/physical_key_data.dart @@ -275,17 +275,20 @@ class PhysicalKeyEntry { /// Populates the key from a JSON map. factory PhysicalKeyEntry.fromJsonMapEntry(Map map) { + final Map names = map['names'] as Map; + final Map scanCodes = map['scanCodes'] as Map; + final Map? keyCodes = map['keyCodes'] as Map?; return PhysicalKeyEntry( - name: map['names']['name'] as String, - chromiumCode: map['names']['chromium'] as String?, - usbHidCode: map['scanCodes']['usb'] as int, - androidScanCodes: (map['scanCodes']['android'] as List?)?.cast() ?? [], - linuxScanCode: map['scanCodes']['linux'] as int?, - xKbScanCode: map['scanCodes']['xkb'] as int?, - windowsScanCode: map['scanCodes']['windows'] as int?, - macOSScanCode: map['scanCodes']['macos'] as int?, - iOSScanCode: map['scanCodes']['ios'] as int?, - glfwKeyCodes: (map['keyCodes']?['glfw'] as List?)?.cast() ?? [], + name: names['name'] as String, + chromiumCode: names['chromium'] as String?, + usbHidCode: scanCodes['usb'] as int, + androidScanCodes: (scanCodes['android'] as List?)?.cast() ?? [], + linuxScanCode: scanCodes['linux'] as int?, + xKbScanCode: scanCodes['xkb'] as int?, + windowsScanCode: scanCodes['windows'] as int?, + macOSScanCode: scanCodes['macos'] as int?, + iOSScanCode: scanCodes['ios'] as int?, + glfwKeyCodes: (keyCodes?['glfw'] as List?)?.cast() ?? [], ); } diff --git a/packages/flutter/lib/src/animation/tween.dart b/packages/flutter/lib/src/animation/tween.dart index 1e64732607..adaf747d5e 100644 --- a/packages/flutter/lib/src/animation/tween.dart +++ b/packages/flutter/lib/src/animation/tween.dart @@ -221,7 +221,7 @@ class _ChainedEvaluation extends Animatable { /// If `T` is not nullable, then [begin] and [end] must both be set to /// non-null values before using [lerp] or [transform], otherwise they /// will throw. -class Tween extends Animatable { +class Tween extends Animatable { /// Creates a tween. /// /// The [begin] and [end] properties must be non-null before the tween is @@ -261,7 +261,8 @@ class Tween extends Animatable { // that do not conform to the Tween requirements. dynamic result; try { - result = begin + (end - begin) * t; + // ignore: avoid_dynamic_calls + result = (begin as dynamic) + ((end as dynamic) - (begin as dynamic)) * t; result as T; return true; } on NoSuchMethodError { @@ -301,7 +302,8 @@ class Tween extends Animatable { ]); } }()); - return begin + (end - begin) * t as T; + // ignore: avoid_dynamic_calls + return (begin as dynamic) + ((end as dynamic) - (begin as dynamic)) * t as T; } /// Returns the interpolated value for the current value of the given animation. @@ -330,7 +332,7 @@ class Tween extends Animatable { } /// A [Tween] that evaluates its [parent] in reverse. -class ReverseTween extends Tween { +class ReverseTween extends Tween { /// Construct a [Tween] that evaluates its [parent] in reverse. ReverseTween(this.parent) : assert(parent != null), diff --git a/packages/flutter/lib/src/foundation/_isolates_io.dart b/packages/flutter/lib/src/foundation/_isolates_io.dart index 1de7de10cc..74db7581b4 100644 --- a/packages/flutter/lib/src/foundation/_isolates_io.dart +++ b/packages/flutter/lib/src/foundation/_isolates_io.dart @@ -35,13 +35,15 @@ Future compute(isolates.ComputeCallback callback, Q message, { St final Completer result = Completer(); errorPort.listen((dynamic errorData) { assert(errorData is List); - assert(errorData.length == 2); - final Exception exception = Exception(errorData[0]); - final StackTrace stack = StackTrace.fromString(errorData[1] as String); - if (result.isCompleted) { - Zone.current.handleUncaughtError(exception, stack); - } else { - result.completeError(exception, stack); + if (errorData is List) { + assert(errorData.length == 2); + final Exception exception = Exception(errorData[0]); + final StackTrace stack = StackTrace.fromString(errorData[1] as String); + if (result.isCompleted) { + Zone.current.handleUncaughtError(exception, stack); + } else { + result.completeError(exception, stack); + } } }); exitPort.listen((dynamic exitData) { diff --git a/packages/flutter/lib/src/painting/_network_image_web.dart b/packages/flutter/lib/src/painting/_network_image_web.dart index 88ff4c8ebf..61543599cb 100644 --- a/packages/flutter/lib/src/painting/_network_image_web.dart +++ b/packages/flutter/lib/src/painting/_network_image_web.dart @@ -86,7 +86,7 @@ class NetworkImage final Uri resolved = Uri.base.resolve(key.url); // This API only exists in the web engine implementation and is not // contained in the analyzer summary for Flutter. - return ui.webOnlyInstantiateImageCodecFromUrl(// ignore: undefined_function + return ui.webOnlyInstantiateImageCodecFromUrl(// ignore: undefined_function, avoid_dynamic_calls resolved, chunkCallback: (int bytes, int total) { chunkEvents.add(ImageChunkEvent(cumulativeBytesLoaded: bytes, expectedTotalBytes: total)); diff --git a/packages/flutter/lib/src/painting/image_cache.dart b/packages/flutter/lib/src/painting/image_cache.dart index 7ef7637ce9..f1e1906915 100644 --- a/packages/flutter/lib/src/painting/image_cache.dart +++ b/packages/flutter/lib/src/painting/image_cache.dart @@ -517,7 +517,7 @@ class ImageCache { image.dispose(); _cache.remove(key); if (!kReleaseMode) { - finishArgs['evictedKeys'].add(key.toString()); + (finishArgs['evictedKeys'] as List).add(key.toString()); } } if (!kReleaseMode) { diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index c45a68bf99..3f3ab6e844 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -1369,8 +1369,10 @@ class TextInput { _currentConnection!._client.performAction(_toTextInputAction(args[1] as String)); break; case 'TextInputClient.performPrivateCommand': + final Map firstArg = args[1] as Map; _currentConnection!._client.performPrivateCommand( - args[1]['action'] as String, args[1]['data'] as Map, + firstArg['action'] as String, + firstArg['data'] as Map, ); break; case 'TextInputClient.updateFloatingCursor': diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 9512101101..bddebac9ac 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -6395,7 +6395,7 @@ FlutterErrorDetails _debugReportException( /// * [RenderObjectElement.updateChildren], which discusses why this class is /// used as slot values for the children of a [MultiChildRenderObjectElement]. @immutable -class IndexedSlot { +class IndexedSlot { /// Creates an [IndexedSlot] with the provided [index] and slot [value]. const IndexedSlot(this.index, this.value); diff --git a/packages/flutter/lib/src/widgets/overscroll_indicator.dart b/packages/flutter/lib/src/widgets/overscroll_indicator.dart index a79225adc5..ffd11f4063 100644 --- a/packages/flutter/lib/src/widgets/overscroll_indicator.dart +++ b/packages/flutter/lib/src/widgets/overscroll_indicator.dart @@ -306,6 +306,9 @@ class _GlowingOverscrollIndicatorState extends State } } } else if (notification is ScrollEndNotification || notification is ScrollUpdateNotification) { + // Using dynamic here to avoid layer violations of importing + // drag_details.dart from gestures. + // ignore: avoid_dynamic_calls if ((notification as dynamic).dragDetails != null) { _leadingController!.scrollEnd(); _trailingController!.scrollEnd(); diff --git a/packages/flutter/test/analysis_options.yaml b/packages/flutter/test/analysis_options.yaml new file mode 100644 index 0000000000..c4f0941e6b --- /dev/null +++ b/packages/flutter/test/analysis_options.yaml @@ -0,0 +1,7 @@ +include: ../analysis_options.yaml + +linter: + rules: + # Turn off for tests, since we often use dynamic as a method to obtain a + # reference to a private state object or renderer in tests. + avoid_dynamic_calls: false diff --git a/packages/flutter/test/services/fake_platform_views.dart b/packages/flutter/test/services/fake_platform_views.dart index 7695c4a92c..9f74afdca4 100644 --- a/packages/flutter/test/services/fake_platform_views.dart +++ b/packages/flutter/test/services/fake_platform_views.dart @@ -209,7 +209,9 @@ class FakeAndroidPlatformViewsController { Future _dispose(MethodCall call) { assert(call.arguments is Map); + // ignore: avoid_dynamic_calls final int id = call.arguments['id'] as int; + // ignore: avoid_dynamic_calls final bool hybrid = call.arguments['hybrid'] as bool; if (hybrid && !_views[id]!.hybrid!) { diff --git a/packages/flutter_driver/lib/src/driver/web_driver.dart b/packages/flutter_driver/lib/src/driver/web_driver.dart index e5229e0905..3017d9fc4b 100644 --- a/packages/flutter_driver/lib/src/driver/web_driver.dart +++ b/packages/flutter_driver/lib/src/driver/web_driver.dart @@ -156,12 +156,12 @@ class WebFlutterDriver extends FlutterDriver { final List> events = >[]; for (final async_io.LogEntry entry in await _connection.logs.toList()) { if (_startTime.isBefore(entry.timestamp)) { - final Map data = jsonDecode(entry.message!)['message'] as Map; + final Map data = (jsonDecode(entry.message!) as Map)['message'] as Map; if (data['method'] == 'Tracing.dataCollected') { // 'ts' data collected from Chrome is in double format, conversion needed try { - data['params']['ts'] = - double.parse(data['params']['ts'].toString()).toInt(); + final Map params = data['params'] as Map; + params['ts'] = double.parse(params['ts'].toString()).toInt(); } on FormatException catch (_) { // data is corrupted, skip continue; diff --git a/packages/flutter_driver/test/src/real_tests/flutter_driver_test.dart b/packages/flutter_driver/test/src/real_tests/flutter_driver_test.dart index c1085f3259..7e39983939 100644 --- a/packages/flutter_driver/test/src/real_tests/flutter_driver_test.dart +++ b/packages/flutter_driver/test/src/real_tests/flutter_driver_test.dart @@ -968,16 +968,16 @@ void main() { }); } -/// This function will verify the format of the script -/// and return the actual script. -/// script will be in the following format: +// This function will verify the format of the script and return the actual +// script. The script will be in the following format: // window.flutterDriver('[actual script]') -String? _checkAndEncode(dynamic script) { +String _checkAndEncode(dynamic script) { expect(script, isA()); - expect(script.startsWith(_kWebScriptPrefix), isTrue); - expect(script.endsWith(_kWebScriptSuffix), isTrue); + final String scriptString = script as String; + expect(scriptString.startsWith(_kWebScriptPrefix), isTrue); + expect(scriptString.endsWith(_kWebScriptSuffix), isTrue); // Strip prefix and suffix - return script.substring(_kWebScriptPrefix.length, script.length - 2) as String?; + return scriptString.substring(_kWebScriptPrefix.length, script.length - 2); } vms.Response? makeFakeResponse( @@ -999,7 +999,7 @@ class FakeFlutterWebConnection extends Fake implements FlutterWebConnection { @override Future sendCommand(String script, Duration? duration) async { commandLog.add('$script $duration'); - final Map decoded = jsonDecode(_checkAndEncode(script)!) as Map; + final Map decoded = jsonDecode(_checkAndEncode(script)) as Map; final dynamic response = responses[decoded['command']]; assert(response != null, 'Missing ${decoded['command']} in responses.'); return response; diff --git a/packages/flutter_localizations/test/material/time_picker_test.dart b/packages/flutter_localizations/test/material/time_picker_test.dart index 1033efd249..ca34c32b36 100644 --- a/packages/flutter_localizations/test/material/time_picker_test.dart +++ b/packages/flutter_localizations/test/material/time_picker_test.dart @@ -345,14 +345,18 @@ void main() { final CustomPaint dialPaint = tester.widget(find.byKey(const ValueKey('time-picker-dial'))); final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls final List primaryLabels = dialPainter.primaryLabels as List; expect( + // ignore: avoid_dynamic_calls primaryLabels.map((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!), labels12To11, ); + // ignore: avoid_dynamic_calls final List secondaryLabels = dialPainter.secondaryLabels as List; expect( + // ignore: avoid_dynamic_calls secondaryLabels.map((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!), labels12To11, ); @@ -363,14 +367,18 @@ void main() { final CustomPaint dialPaint = tester.widget(find.byKey(const ValueKey('time-picker-dial'))); final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls final List primaryLabels = dialPainter.primaryLabels as List; expect( + // ignore: avoid_dynamic_calls primaryLabels.map((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!), labels00To22TwoDigit, ); + // ignore: avoid_dynamic_calls final List secondaryLabels = dialPainter.secondaryLabels as List; expect( + // ignore: avoid_dynamic_calls secondaryLabels.map((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!), labels00To22TwoDigit, ); diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart index 43b9eee692..4addf8bde6 100644 --- a/packages/flutter_test/lib/src/matchers.dart +++ b/packages/flutter_test/lib/src/matchers.dart @@ -866,7 +866,7 @@ class _HasGoodToStringDeep extends Matcher { @override bool matches(dynamic object, Map matchState) { final List issues = []; - String description = object.toStringDeep() as String; + String description = object.toStringDeep() as String; // ignore: avoid_dynamic_calls if (description.endsWith('\n')) { // Trim off trailing \n as the remaining calculations assume // the description does not end with a trailing \n. @@ -904,7 +904,7 @@ class _HasGoodToStringDeep extends Matcher { const String prefixOtherLines = 'PREFIX_OTHER_LINES_'; final List prefixIssues = []; String descriptionWithPrefixes = - object.toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines) as String; + object.toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines) as String; // ignore: avoid_dynamic_calls if (descriptionWithPrefixes.endsWith('\n')) { // Trim off trailing \n as the remaining calculations assume // the description does not end with a trailing \n. @@ -1875,7 +1875,7 @@ class _MatchesSemanticsData extends Matcher { bool allMatched = true; if (children != null) { int i = 0; - node.visitChildren((SemanticsNode child) { + (node as SemanticsNode).visitChildren((SemanticsNode child) { allMatched = children![i].matches(child, matchState) && allMatched; i += 1; return allMatched; diff --git a/packages/flutter_test/lib/src/test_text_input.dart b/packages/flutter_test/lib/src/test_text_input.dart index 74554d3032..114f5ee831 100644 --- a/packages/flutter_test/lib/src/test_text_input.dart +++ b/packages/flutter_test/lib/src/test_text_input.dart @@ -119,8 +119,9 @@ class TestTextInput { log.add(methodCall); switch (methodCall.method) { case 'TextInput.setClient': - _client = methodCall.arguments[0] as int; - setClientArgs = methodCall.arguments[1] as Map; + final List arguments = methodCall.arguments as List; + _client = arguments[0] as int; + setClientArgs = arguments[1] as Map; break; case 'TextInput.updateConfig': setClientArgs = methodCall.arguments as Map; diff --git a/packages/flutter_test/test/window_test.dart b/packages/flutter_test/test/window_test.dart index 2f060b51e5..56a283c440 100644 --- a/packages/flutter_test/test/window_test.dart +++ b/packages/flutter_test/test/window_test.dart @@ -11,6 +11,7 @@ import 'package:flutter_test/flutter_test.dart'; void main() { test('TestWindow can handle new methods without breaking', () { final dynamic testWindow = TestWindow(window: ui.window); + // ignore: avoid_dynamic_calls expect(testWindow.someNewProperty, null); }); diff --git a/packages/flutter_tools/lib/src/base/multi_root_file_system.dart b/packages/flutter_tools/lib/src/base/multi_root_file_system.dart index 4c787c6843..217cff5682 100644 --- a/packages/flutter_tools/lib/src/base/multi_root_file_system.dart +++ b/packages/flutter_tools/lib/src/base/multi_root_file_system.dart @@ -126,7 +126,7 @@ class MultiRootFileSystem extends ForwardingFileSystem { } else if (path is FileSystemEntity) { uri = path.uri; } else { - throw ArgumentError('Invalid type for "path": ${path?.runtimeType}'); + throw ArgumentError('Invalid type for "path": ${(path as Object?)?.runtimeType}'); } if (!uri.hasScheme || uri.scheme != _scheme) { diff --git a/packages/flutter_tools/lib/src/build_system/targets/web.dart b/packages/flutter_tools/lib/src/build_system/targets/web.dart index 640a54348a..7a6096af90 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/web.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/web.dart @@ -15,6 +15,7 @@ import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../build_info.dart'; import '../../cache.dart'; +import '../../convert.dart'; import '../../dart/language_version.dart'; import '../../dart/package_map.dart'; import '../../globals_null_migrated.dart' as globals; @@ -198,6 +199,16 @@ class Dart2JSTarget extends Target { 'dart2js.d', ]; + String _collectOutput(ProcessResult result) { + final String stdout = result.stdout is List + ? utf8.decode(result.stdout as List) + : result.stdout as String; + final String stderr = result.stderr is List + ? utf8.decode(result.stderr as List) + : result.stderr as String; + return stdout + stderr; + } + @override Future build(Environment environment) async { final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); @@ -233,7 +244,7 @@ class Dart2JSTarget extends Target { environment.buildDir.childFile('main.dart').path, // dartfile ]); if (kernelResult.exitCode != 0) { - throw Exception(kernelResult.stdout + kernelResult.stderr); + throw Exception(_collectOutput(kernelResult)); } final String dart2jsOptimization = environment.defines[kDart2jsOptimization]; @@ -250,7 +261,7 @@ class Dart2JSTarget extends Target { environment.buildDir.childFile('app.dill').path, // dartfile ]); if (javaScriptResult.exitCode != 0) { - throw Exception(javaScriptResult.stdout + javaScriptResult.stderr); + throw Exception(_collectOutput(javaScriptResult)); } final File dart2jsDeps = environment.buildDir .childFile('app.dill.deps'); diff --git a/packages/flutter_tools/lib/src/dart/analysis.dart b/packages/flutter_tools/lib/src/dart/analysis.dart index 43dd3ee9cc..e5f572e56b 100644 --- a/packages/flutter_tools/lib/src/dart/analysis.dart +++ b/packages/flutter_tools/lib/src/dart/analysis.dart @@ -150,7 +150,7 @@ class AnalysisServer { void _handleStatus(Map statusInfo) { // {"event":"server.status","params":{"analysis":{"isAnalyzing":true}}} if (statusInfo['analysis'] != null && !_analyzingController.isClosed) { - final bool isAnalyzing = statusInfo['analysis']['isAnalyzing'] as bool; + final bool isAnalyzing = (statusInfo['analysis'] as Map)['isAnalyzing'] as bool; _analyzingController.add(isAnalyzing); } } @@ -293,15 +293,16 @@ class WrittenError { /// "hasFix":false /// } static WrittenError fromJson(Map json) { + final Map location = json['location'] as Map; return WrittenError._( severity: json['severity'] as String, type: json['type'] as String, message: json['message'] as String, code: json['code'] as String, - file: json['location']['file'] as String, - startLine: json['location']['startLine'] as int, - startColumn: json['location']['startColumn'] as int, - offset: json['location']['offset'] as int, + file: location['file'] as String, + startLine: location['startLine'] as int, + startColumn: location['startColumn'] as int, + offset: location['offset'] as int, ); } diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart index 24946ff877..423661ebbf 100644 --- a/packages/flutter_tools/lib/src/dart/pub.dart +++ b/packages/flutter_tools/lib/src/dart/pub.dart @@ -496,10 +496,10 @@ class _DefaultPub implements Pub { // Because [loadPackageConfigWithLogging] succeeded [packageConfigFile] // we can rely on the file to exist and be correctly formatted. - final dynamic jsonContents = - json.decode(packageConfigFile.readAsStringSync()); + final Map jsonContents = + json.decode(packageConfigFile.readAsStringSync()) as Map; - jsonContents['packages'].add({ + (jsonContents['packages'] as List).add({ 'name': 'flutter_gen', 'rootUri': 'flutter_gen', 'languageVersion': '2.12', diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart index f6258b8d16..89d3066c3b 100644 --- a/packages/flutter_tools/lib/src/flutter_manifest.dart +++ b/packages/flutter_tools/lib/src/flutter_manifest.dart @@ -247,7 +247,7 @@ class FlutterManifest { DeferredComponent( name: component['name'] as String, libraries: component['libraries'] == null ? - [] : component['libraries'].cast() as List, + [] : (component['libraries'] as List).cast(), assets: assetsUri, ) ); @@ -571,6 +571,7 @@ void _validateFlutter(YamlMap? yaml, List errors) { void _validateListType(YamlList yamlList, List errors, String context, String typeAlias) { for (int i = 0; i < yamlList.length; i++) { if (yamlList[i] is! T) { + // ignore: avoid_dynamic_calls errors.add('Expected $context to be a list of $typeAlias, but element $i was a ${yamlList[i].runtimeType}'); } } @@ -584,6 +585,7 @@ void _validateDeferredComponents(MapEntry kvp, List er for (int i = 0; i < yamlList.length; i++) { final Object? valueMap = yamlList[i]; if (valueMap is! YamlMap) { + // ignore: avoid_dynamic_calls errors.add('Expected the $i element in "${kvp.key}" to be a map, but got ${yamlList[i]} (${yamlList[i].runtimeType}).'); continue; } diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index 9151eed338..ce085ab264 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart @@ -130,7 +130,7 @@ class SimControl { return >{}; } try { - final Object decodeResult = json.decode(results.stdout)[section.name]; + final Object decodeResult = (json.decode(results.stdout) as Map)[section.name]; if (decodeResult is Map) { return decodeResult; } diff --git a/packages/flutter_tools/lib/src/macos/xcdevice.dart b/packages/flutter_tools/lib/src/macos/xcdevice.dart index 493c26db61..bc611cb790 100644 --- a/packages/flutter_tools/lib/src/macos/xcdevice.dart +++ b/packages/flutter_tools/lib/src/macos/xcdevice.dart @@ -269,55 +269,52 @@ class XCDevice { final List devices = []; for (final dynamic device in allAvailableDevices) { - if (device is! Map) { - continue; - } - final Map deviceProperties = device as Map; - - // Only include iPhone, iPad, iPod, or other iOS devices. - if (!_isIPhoneOSDevice(deviceProperties)) { - continue; - } - - final Map errorProperties = _errorProperties(deviceProperties); - if (errorProperties != null) { - final String errorMessage = _parseErrorMessage(errorProperties); - if (errorMessage.contains('not paired')) { - UsageEvent('device', 'ios-trust-failure', flutterUsage: globals.flutterUsage).send(); - } - _logger.printTrace(errorMessage); - - final int code = _errorCode(errorProperties); - - // Temporary error -10: iPhone is busy: Preparing debugger support for iPhone. - // Sometimes the app launch will fail on these devices until Xcode is done setting up the device. - // Other times this is a false positive and the app will successfully launch despite the error. - if (code != -10) { + if (device is Map) { + // Only include iPhone, iPad, iPod, or other iOS devices. + if (!_isIPhoneOSDevice(device)) { continue; } + + final Map errorProperties = _errorProperties(device); + if (errorProperties != null) { + final String errorMessage = _parseErrorMessage(errorProperties); + if (errorMessage.contains('not paired')) { + UsageEvent('device', 'ios-trust-failure', flutterUsage: globals.flutterUsage).send(); + } + _logger.printTrace(errorMessage); + + final int code = _errorCode(errorProperties); + + // Temporary error -10: iPhone is busy: Preparing debugger support for iPhone. + // Sometimes the app launch will fail on these devices until Xcode is done setting up the device. + // Other times this is a false positive and the app will successfully launch despite the error. + if (code != -10) { + continue; + } + } + + final IOSDeviceInterface interface = _interfaceType(device); + + // Only support USB devices, skip "network" interface (Xcode > Window > Devices and Simulators > Connect via network). + // TODO(jmagman): Remove this check once wirelessly detected devices can be observed and attached, https://github.com/flutter/flutter/issues/15072. + if (interface != IOSDeviceInterface.usb) { + continue; + } + + devices.add(IOSDevice( + device['identifier'] as String, + name: device['name'] as String, + cpuArchitecture: _cpuArchitecture(device), + interfaceType: interface, + sdkVersion: _sdkVersion(device), + iProxy: _iProxy, + fileSystem: globals.fs, + logger: _logger, + iosDeploy: _iosDeploy, + iMobileDevice: _iMobileDevice, + platform: globals.platform, + )); } - - final IOSDeviceInterface interface = _interfaceType(deviceProperties); - - // Only support USB devices, skip "network" interface (Xcode > Window > Devices and Simulators > Connect via network). - // TODO(jmagman): Remove this check once wirelessly detected devices can be observed and attached, https://github.com/flutter/flutter/issues/15072. - if (interface != IOSDeviceInterface.usb) { - continue; - } - - devices.add(IOSDevice( - device['identifier'] as String, - name: device['name'] as String, - cpuArchitecture: _cpuArchitecture(deviceProperties), - interfaceType: interface, - sdkVersion: _sdkVersion(deviceProperties), - iProxy: _iProxy, - fileSystem: globals.fs, - logger: _logger, - iosDeploy: _iosDeploy, - iMobileDevice: _iMobileDevice, - platform: globals.platform, - )); } return devices; } diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart index 2cba9ee9d9..781fcc6669 100644 --- a/packages/flutter_tools/lib/src/plugins.dart +++ b/packages/flutter_tools/lib/src/plugins.dart @@ -89,13 +89,12 @@ class Plugin { factory Plugin._fromMultiPlatformYaml( String name, String path, - dynamic pluginYaml, + YamlMap pluginYaml, List dependencies, FileSystem fileSystem, bool isDirectDependency, ) { - assert (pluginYaml != null && pluginYaml['platforms'] != null, - 'Invalid multi-platform plugin specification $name.'); + assert (pluginYaml['platforms'] != null, 'Invalid multi-platform plugin specification $name.'); final YamlMap platformsYaml = pluginYaml['platforms'] as YamlMap; assert (_validateMultiPlatformYaml(platformsYaml).isEmpty, @@ -190,7 +189,7 @@ class Plugin { bool isDirectDependency, ) { final Map platforms = {}; - final String pluginClass = pluginYaml['pluginClass'] as String; + final String pluginClass = (pluginYaml as Map)['pluginClass'] as String; if (pluginYaml != null && pluginClass != null) { final String androidPackage = pluginYaml['androidPackage'] as String; if (androidPackage != null) { diff --git a/packages/flutter_tools/lib/src/protocol_discovery.dart b/packages/flutter_tools/lib/src/protocol_discovery.dart index a0c96adcc1..2a36d8b306 100644 --- a/packages/flutter_tools/lib/src/protocol_discovery.dart +++ b/packages/flutter_tools/lib/src/protocol_discovery.dart @@ -177,8 +177,8 @@ class _BufferedStreamController { _streamControllerInstance.add(event); } else { _streamControllerInstance.addError( - event.first as Object, - event.last as StackTrace, + (event as Iterable).first as Object, + (event as Iterable).last as StackTrace, ); } } diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 900f045f6e..5b1f956eb9 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -1118,8 +1118,9 @@ Future _defaultReloadSourcesHelper( // refactored, we'll probably need to send one hot reload/restart event // per device to analytics. firstReloadDetails.addAll(castStringKeyedMap(reloadReport.json['details'])); - final int loadedLibraryCount = reloadReport.json['details']['loadedLibraryCount'] as int; - final int finalLibraryCount = reloadReport.json['details']['finalLibraryCount'] as int; + final Map details = reloadReport.json['details'] as Map; + final int loadedLibraryCount = details['loadedLibraryCount'] as int; + final int finalLibraryCount = details['finalLibraryCount'] as int; globals.printTrace('reloaded $loadedLibraryCount of $finalLibraryCount libraries'); // reloadMessage = 'Reloaded $loadedLibraryCount of $finalLibraryCount libraries'; // Record time it took for the VM to reload the sources. diff --git a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart index c168d7c177..cd0a534cb2 100644 --- a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart @@ -737,21 +737,24 @@ class BrowserManager { /// The callback for handling messages received from the host page. void _onMessage(dynamic message) { - switch (message['command'] as String) { - case 'ping': - break; - case 'restart': - _onRestartController.add(null); - break; - case 'resume': - if (_pauseCompleter != null) { - _pauseCompleter.complete(); - } - break; - default: + assert(message is Map); + if (message is Map) { + switch (message['command'] as String) { + case 'ping': + break; + case 'restart': + _onRestartController.add(null); + break; + case 'resume': + if (_pauseCompleter != null) { + _pauseCompleter.complete(); + } + break; + default: // Unreachable. - assert(false); - break; + assert(false); + break; + } } } diff --git a/packages/flutter_tools/lib/src/windows/visual_studio.dart b/packages/flutter_tools/lib/src/windows/visual_studio.dart index 0d4374b20e..f06b474818 100644 --- a/packages/flutter_tools/lib/src/windows/visual_studio.dart +++ b/packages/flutter_tools/lib/src/windows/visual_studio.dart @@ -56,7 +56,7 @@ class VisualStudio { if (_bestVisualStudioDetails[_catalogKey] == null) { return null; } - return _bestVisualStudioDetails[_catalogKey][_catalogDisplayVersionKey] as String?; + return (_bestVisualStudioDetails[_catalogKey] as Map)[_catalogDisplayVersionKey] as String?; } /// The directory where Visual Studio is installed. diff --git a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart index 7df7498604..1796f468e3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart @@ -52,13 +52,14 @@ void main() { expect(testLogger.statusText, isNotEmpty); final dynamic jsonObject = json.decode(testLogger.statusText); - expect(jsonObject, isMap); + expect(jsonObject, const TypeMatcher>()); + if (jsonObject is Map) { + expect(jsonObject.containsKey('android-studio-dir'), true); + expect(jsonObject['android-studio-dir'], isNotNull); - expect(jsonObject.containsKey('android-studio-dir'), true); - expect(jsonObject['android-studio-dir'], isNotNull); - - expect(jsonObject.containsKey('android-sdk'), true); - expect(jsonObject['android-sdk'], isNotNull); + expect(jsonObject.containsKey('android-sdk'), true); + expect(jsonObject['android-sdk'], isNotNull); + } verifyNoAnalytics(); }, overrides: { AndroidStudio: () => fakeAndroidStudio, diff --git a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart index 63bc51486d..028cba970e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart @@ -93,7 +93,7 @@ void main() { expect(response['id'], 0); expect(response['result'], isNotEmpty); - expect(response['result']['platforms'], {'macos'}); + expect((response['result'] as Map)['platforms'], {'macos'}); await responses.close(); await commands.close(); }, overrides: { @@ -111,7 +111,7 @@ void main() { ); globals.printError('daemon.logMessage test'); final Map response = await responses.stream.firstWhere((Map map) { - return map['event'] == 'daemon.logMessage' && map['params']['level'] == 'error'; + return map['event'] == 'daemon.logMessage' && (map['params'] as Map)['level'] == 'error'; }); expect(response['id'], isNull); expect(response['event'], 'daemon.logMessage'); @@ -347,7 +347,7 @@ void main() { unawaited(output.stream .firstWhere((Map request) => request['method'] == 'app.exposeUrl') .then((Map request) { - expect(request['params']['url'], equals(originalUrl)); + expect((request['params'] as Map)['url'], equals(originalUrl)); input.add({'id': request['id'], 'result': {'url': mappedUrl}}); }) ); @@ -370,9 +370,10 @@ void main() { commands.add({'id': 0, 'method': 'devtools.serve'}); final Map response = await responses.stream.firstWhere((Map response) => response['id'] == 0); - expect(response['result'], isNotEmpty); - expect(response['result']['host'], '127.0.0.1'); - expect(response['result']['port'], 1234); + final Map result = response['result'] as Map; + expect(result, isNotEmpty); + expect(result['host'], '127.0.0.1'); + expect(result['port'], 1234); await responses.close(); await commands.close(); }, overrides: { @@ -390,9 +391,10 @@ void main() { commands.add({'id': 0, 'method': 'devtools.serve'}); final Map response = await responses.stream.firstWhere((Map response) => response['id'] == 0); - expect(response['result'], isNotEmpty); - expect(response['result']['host'], null); - expect(response['result']['port'], null); + final Map result = response['result'] as Map; + expect(result, isNotEmpty); + expect(result['host'], null); + expect(result['port'], null); await responses.close(); await commands.close(); }, overrides: { diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 63ea718034..93dee598ac 100755 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -28,6 +28,7 @@ import 'package:process/process.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:pubspec_parse/pubspec_parse.dart'; import 'package:uuid/uuid.dart'; +import 'package:yaml/yaml.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -482,8 +483,9 @@ void main() { // Expect the dependency on flutter_web_plugins exists expect(pubspec.dependencies, contains('flutter_web_plugins')); // The platform is correctly registered - expect(pubspec.flutter['plugin']['platforms']['web']['pluginClass'], 'FlutterProjectWeb'); - expect(pubspec.flutter['plugin']['platforms']['web']['fileName'], 'flutter_project_web.dart'); + final YamlMap web = ((pubspec.flutter['plugin'] as YamlMap)['platforms'] as YamlMap)['web'] as YamlMap; + expect(web['pluginClass'], 'FlutterProjectWeb'); + expect(web['fileName'], 'flutter_project_web.dart'); expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), diff --git a/packages/flutter_tools/test/general.shard/base/analyze_size_test.dart b/packages/flutter_tools/test/general.shard/base/analyze_size_test.dart index 46b576b7c2..f4dbeb7fd9 100644 --- a/packages/flutter_tools/test/general.shard/base/analyze_size_test.dart +++ b/packages/flutter_tools/test/general.shard/base/analyze_size_test.dart @@ -90,47 +90,54 @@ void main() { ); expect(result['type'], 'apk'); - - final Map androidManifestMap = result['children'][0] as Map; + final List resultChildren = result['children'] as List; + final Map androidManifestMap = resultChildren[0] as Map; expect(androidManifestMap['n'], 'AndroidManifest.xml'); expect(androidManifestMap['value'], 6); - final Map metaInfMap = result['children'][1] as Map; + final Map metaInfMap = resultChildren[1] as Map; + final List> metaInfMapChildren = metaInfMap['children']! as List>; expect(metaInfMap['n'], 'META-INF'); expect(metaInfMap['value'], 10); - final Map certRsaMap = metaInfMap['children'][0] as Map; + final Map certRsaMap = metaInfMapChildren[0]; expect(certRsaMap['n'], 'CERT.RSA'); expect(certRsaMap['value'], 5); - final Map certSfMap = metaInfMap['children'][1] as Map; + final Map certSfMap = metaInfMapChildren[1]; expect(certSfMap['n'], 'CERT.SF'); expect(certSfMap['value'], 5); - final Map libMap = result['children'][2] as Map; + final Map libMap = resultChildren[2] as Map; + final List> libMapChildren = libMap['children']! as List>; expect(libMap['n'], 'lib'); expect(libMap['value'], 12); - final Map arm64Map = libMap['children'][0] as Map; + final Map arm64Map = libMapChildren[0]; + final List> arn64MapChildren = arm64Map['children']! as List>; expect(arm64Map['n'], 'arm64-v8a'); expect(arm64Map['value'], 12); - final Map libAppMap = arm64Map['children'][0] as Map; + final Map libAppMap = arn64MapChildren[0]; + final List libAppMapChildren = libAppMap['children']! as List; expect(libAppMap['n'], 'libxyzzyapp.so (Dart AOT)'); expect(libAppMap['value'], 6); - expect(libAppMap['children'].length, 3); - final Map internalMap = libAppMap['children'][0] as Map; - final Map skipMap = internalMap['children'][0] as Map; + expect(libAppMapChildren.length, 3); + final Map internalMap = libAppMapChildren[0] as Map; + final List internalMapChildren = internalMap['children']! as List; + final Map skipMap = internalMapChildren[0] as Map; expect(skipMap['n'], 'skip'); expect(skipMap['value'], 2400); - final Map subListIterableMap = internalMap['children'][1] as Map; + final Map subListIterableMap = internalMapChildren[1] as Map; expect(subListIterableMap['n'], 'new SubListIterable.'); expect(subListIterableMap['value'], 3560); - final Map coreMap = libAppMap['children'][1] as Map; - final Map rangeErrorMap = coreMap['children'][0] as Map; + final Map coreMap = libAppMapChildren[1] as Map; + final List coreMapChildren = coreMap['children']! as List; + final Map rangeErrorMap = coreMapChildren[0] as Map; expect(rangeErrorMap['n'], 'new RangeError.range'); expect(rangeErrorMap['value'], 3920); - final Map stubsMap = libAppMap['children'][2] as Map; - final Map allocateMap = stubsMap['children'][0] as Map; + final Map stubsMap = libAppMapChildren[2] as Map; + final List stubsMapChildren = stubsMap['children']! as List; + final Map allocateMap = stubsMapChildren[0] as Map; expect(allocateMap['n'], 'Allocate ArgumentError'); expect(allocateMap['value'], 4650); - final Map libFlutterMap = arm64Map['children'][1] as Map; + final Map libFlutterMap = arn64MapChildren[1]; expect(libFlutterMap['n'], 'libflutter.so (Flutter Engine)'); expect(libFlutterMap['value'], 6); diff --git a/packages/flutter_tools/test/general.shard/base/fingerprint_test.dart b/packages/flutter_tools/test/general.shard/base/fingerprint_test.dart index d7e9b190f4..b51970d554 100644 --- a/packages/flutter_tools/test/general.shard/base/fingerprint_test.dart +++ b/packages/flutter_tools/test/general.shard/base/fingerprint_test.dart @@ -104,9 +104,10 @@ void main() { final Fingerprint fingerprint = Fingerprint.fromBuildInputs(const ['a.dart', 'b.dart'], fileSystem); final Map? jsonObject = castStringKeyedMap(json.decode(fingerprint.toJson())); - expect(jsonObject!['files'], hasLength(2)); - expect(jsonObject['files']['a.dart'], '8a21a15fad560b799f6731d436c1b698'); - expect(jsonObject['files']['b.dart'], '6f144e08b58cd0925328610fad7ac07c'); + final Map files = jsonObject!['files'] as Map; + expect(files, hasLength(2)); + expect(files['a.dart'], '8a21a15fad560b799f6731d436c1b698'); + expect(files['b.dart'], '6f144e08b58cd0925328610fad7ac07c'); }); }); @@ -124,10 +125,11 @@ void main() { }); final Fingerprint fingerprint = Fingerprint.fromJson(jsonString); final Map? content = castStringKeyedMap(json.decode(fingerprint.toJson())); + final Map files = content!['files'] as Map; expect(content, hasLength(1)); - expect(content!['files'], hasLength(2)); - expect(content['files']['a.dart'], '8a21a15fad560b799f6731d436c1b698'); - expect(content['files']['b.dart'], '6f144e08b58cd0925328610fad7ac07c'); + expect(files, hasLength(2)); + expect(files['a.dart'], '8a21a15fad560b799f6731d436c1b698'); + expect(files['b.dart'], '6f144e08b58cd0925328610fad7ac07c'); }); testWithoutContext('treats missing properties and files entries as if empty', () { final String jsonString = json.encode({}); diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index af5616205f..b0ea3f1014 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -284,7 +284,7 @@ void main() { version: 1.0.0+3 ''', logger: BufferLogger.test()); final FlutterProject project = FlutterProject(fileSystem.systemTempDirectory,manifest,manifest); - final dynamic versionInfo = jsonDecode(project.getVersionInfo()); + final Map versionInfo = jsonDecode(project.getVersionInfo()) as Map; expect(versionInfo['app_name'],'test'); expect(versionInfo['version'],'1.0.0'); expect(versionInfo['build_number'],'3'); diff --git a/packages/flutter_tools/test/integration.shard/command_output_test.dart b/packages/flutter_tools/test/integration.shard/command_output_test.dart index 1297a8bf7a..cd0c4eefa7 100644 --- a/packages/flutter_tools/test/integration.shard/command_output_test.dart +++ b/packages/flutter_tools/test/integration.shard/command_output_test.dart @@ -81,7 +81,7 @@ void main() { ]); // contains all of the experiments in features.dart - expect(result.stdout.split('\n'), containsAll([ + expect((result.stdout as String).split('\n'), containsAll([ for (final Feature feature in allFeatures) contains(feature.configSetting), ])); diff --git a/packages/flutter_tools/test/integration.shard/flutter_gen_test.dart b/packages/flutter_tools/test/integration.shard/flutter_gen_test.dart index 53dfa92030..192e24ac0d 100644 --- a/packages/flutter_tools/test/integration.shard/flutter_gen_test.dart +++ b/packages/flutter_tools/test/integration.shard/flutter_gen_test.dart @@ -35,8 +35,8 @@ void main() { .childDirectory('.dart_tool') .childFile('package_config.json') .readAsStringSync()); - final dynamic collection = jsonContent['packages'] - .firstWhere((dynamic e) => e['name'] == 'collection'); + final Map collection = ((jsonContent as Map)['packages'] as Iterable) + .firstWhere((dynamic entry) => (entry as Map)['name'] == 'collection') as Map; expect( Uri.parse(collection['rootUri'] as String).isAbsolute, isTrue, diff --git a/packages/flutter_tools/test/integration.shard/hot_reload_test.dart b/packages/flutter_tools/test/integration.shard/hot_reload_test.dart index 62c5d76628..86eb9e0a58 100644 --- a/packages/flutter_tools/test/integration.shard/hot_reload_test.dart +++ b/packages/flutter_tools/test/integration.shard/hot_reload_test.dart @@ -190,6 +190,6 @@ bool _isHotReloadCompletionEvent(Map event) { return event != null && event['event'] == 'app.progress' && event['params'] != null && - event['params']['progressId'] == 'hot.reload' && - event['params']['finished'] == true; + (event['params'] as Map)['progressId'] == 'hot.reload' && + (event['params'] as Map)['finished'] == true; } diff --git a/packages/flutter_tools/test/integration.shard/test_driver.dart b/packages/flutter_tools/test/integration.shard/test_driver.dart index 8b91933742..596a5bf167 100644 --- a/packages/flutter_tools/test/integration.shard/test_driver.dart +++ b/packages/flutter_tools/test/integration.shard/test_driver.dart @@ -387,11 +387,14 @@ abstract class FlutterTestDriver { await subscription.cancel(); final StringBuffer error = StringBuffer(); error.write('Received app.stop event while waiting for $interestingOccurrence\n\n$_errorBuffer'); - if (json['params'] != null && json['params']['error'] != null) { - error.write('${json['params']['error']}\n\n'); - } - if (json['params'] != null && json['params']['trace'] != null) { - error.write('${json['params']['trace']}\n\n'); + if (json['params'] != null) { + final Map params = json['params'] as Map; + if (params['error'] != null) { + error.write('${params['error']}\n\n'); + } + if (json['params'] != null && params['trace'] != null) { + error.write('${params['trace']}\n\n'); + } } response.completeError(Exception(error.toString())); } @@ -563,7 +566,7 @@ class FlutterRunTestDriver extends FlutterTestDriver { // _process.kill() (`flutter` is a shell script so _process itself is a // shell, not the flutter tool's Dart process). final Map connected = await _waitFor(event: 'daemon.connected'); - _processPid = connected['params']['pid'] as int; + _processPid = (connected['params'] as Map)['pid'] as int; // Set this up now, but we don't wait it yet. We want to make sure we don't // miss it while waiting for debugPort below. @@ -571,7 +574,7 @@ class FlutterRunTestDriver extends FlutterTestDriver { if (withDebugger) { final Map debugPort = await _waitFor(event: 'app.debugPort', timeout: appStartTimeout); - final String wsUriString = debugPort['params']['wsUri'] as String; + final String wsUriString = (debugPort['params'] as Map)['wsUri'] as String; _vmServiceWsUri = Uri.parse(wsUriString); await connectToVmService(pauseOnExceptions: pauseOnExceptions); if (!startPaused) { @@ -588,7 +591,7 @@ class FlutterRunTestDriver extends FlutterTestDriver { // Now await the started event; if it had already happened the future will // have already completed. - _currentRunningAppId = (await started)['params']['appId'] as String; + _currentRunningAppId = ((await started)['params'] as Map)['appId'] as String; prematureExitGuard.complete(); } on Exception catch (error, stackTrace) { prematureExitGuard.completeError(Exception(error.toString()), stackTrace); @@ -618,10 +621,10 @@ class FlutterRunTestDriver extends FlutterTestDriver { } _debugPrint('Performing ${ pause ? "paused " : "" }${ fullRestart ? "hot restart" : "hot reload" }...'); - final dynamic hotReloadResponse = await _sendRequest( + final Map hotReloadResponse = await _sendRequest( 'app.restart', {'appId': _currentRunningAppId, 'fullRestart': fullRestart, 'pause': pause, 'debounce': debounce, 'debounceDurationOverrideMs': debounceDurationOverrideMs}, - ); + ) as Map; _debugPrint('${fullRestart ? "Hot restart" : "Hot reload"} complete.'); if (hotReloadResponse == null || hotReloadResponse['code'] != 0) { @@ -760,8 +763,9 @@ class FlutterTestTestDriver extends FlutterTestDriver { _processPid = version['pid'] as int; if (withDebugger) { - final Map startedProcess = await _waitFor(event: 'test.startedProcess', timeout: appStartTimeout); - final String vmServiceHttpString = startedProcess['params']['observatoryUri'] as String; + final Map startedProcessParams = + (await _waitFor(event: 'test.startedProcess', timeout: appStartTimeout))['params'] as Map; + final String vmServiceHttpString = startedProcessParams['observatoryUri'] as String; _vmServiceWsUri = Uri.parse(vmServiceHttpString).replace(scheme: 'ws', path: '/ws'); await connectToVmService(pauseOnExceptions: pauseOnExceptions); // Allow us to run code before we start, eg. to set up breakpoints. @@ -824,7 +828,7 @@ Stream transformToLines(Stream> byteStream) { Map parseFlutterResponse(String line) { if (line.startsWith('[') && line.endsWith(']') && line.length > 2) { try { - final Map response = castStringKeyedMap(json.decode(line)[0]); + final Map response = castStringKeyedMap((json.decode(line) as List)[0]); return response; } on FormatException { // Not valid JSON, so likely some other output that was surrounded by [brackets] diff --git a/packages/flutter_tools/test/src/pubspec_schema.dart b/packages/flutter_tools/test/src/pubspec_schema.dart index 1b80a87a18..e2b18fa61e 100644 --- a/packages/flutter_tools/test/src/pubspec_schema.dart +++ b/packages/flutter_tools/test/src/pubspec_schema.dart @@ -19,18 +19,19 @@ void validatePubspecForPlugin({ }) { final FlutterManifest manifest = FlutterManifest.createFromPath('$projectDir/pubspec.yaml', fileSystem: globals.fs, logger: globals.logger)!; - final YamlMap platformsMap = YamlMap.wrap(manifest.supportedPlatforms!); + final YamlMap platformMaps = YamlMap.wrap(manifest.supportedPlatforms!); for (final String platform in expectedPlatforms) { - expect(platformsMap[platform], isNotNull); - expect(platformsMap[platform]['pluginClass'], pluginClass); + expect(platformMaps[platform], isNotNull); + final YamlMap platformMap = platformMaps[platform]! as YamlMap; + expect(platformMap['pluginClass'], pluginClass); if (platform == 'android') { - expect(platformsMap[platform]['package'], androidIdentifier); + expect(platformMap['package'], androidIdentifier); } if (platform == 'web') { - expect(platformsMap[platform]['fileName'], webFileName); + expect(platformMap['fileName'], webFileName); } } for (final String platform in unexpectedPlatforms) { - expect(platformsMap[platform], isNull); + expect(platformMaps[platform], isNull); } } diff --git a/packages/flutter_web_plugins/lib/src/plugin_registry.dart b/packages/flutter_web_plugins/lib/src/plugin_registry.dart index cc397b7c3c..098dec01f8 100644 --- a/packages/flutter_web_plugins/lib/src/plugin_registry.dart +++ b/packages/flutter_web_plugins/lib/src/plugin_registry.dart @@ -62,7 +62,7 @@ class Registrar extends BinaryMessenger { /// compiling for the web. void registerMessageHandler() { // The `ui.webOnlySetPluginHandler` function below is only defined in the Web dart:ui. - // ignore: undefined_function + // ignore: undefined_function, avoid_dynamic_calls ui.webOnlySetPluginHandler(handleFrameworkMessage); } diff --git a/packages/integration_test/lib/integration_test_driver_extended.dart b/packages/integration_test/lib/integration_test_driver_extended.dart index b1e5945ba2..4d1c4fc4b2 100644 --- a/packages/integration_test/lib/integration_test_driver_extended.dart +++ b/packages/integration_test/lib/integration_test_driver_extended.dart @@ -9,10 +9,13 @@ import 'package:flutter_driver/flutter_driver.dart'; import 'common.dart'; +/// A callback to use with [integrationDriver]. +typedef ScreenshotCallback = Future Function(String name, List image); + /// Example Integration Test which can also run WebDriver command depending on /// the requests coming from the test methods. Future integrationDriver( - {FlutterDriver? driver, Function? onScreenshot}) async { + {FlutterDriver? driver, ScreenshotCallback? onScreenshot}) async { driver ??= await FlutterDriver.connect(); // Test states that it's waiting on web driver commands. // [DriverTestMessage] is converted to string since json format causes an @@ -28,11 +31,12 @@ Future integrationDriver( response.data!['web_driver_command'] != '${WebDriverCommandType.noop}') { final String? webDriverCommand = response.data!['web_driver_command'] as String?; if (webDriverCommand == '${WebDriverCommandType.screenshot}') { + assert(onScreenshot != null, 'screenshot command requires an onScreenshot callback'); // Use `driver.screenshot()` method to get a screenshot of the web page. final List screenshotImage = await driver.screenshot(); - final String? screenshotName = response.data!['screenshot_name'] as String?; + final String screenshotName = response.data!['screenshot_name']! as String; - final bool screenshotSuccess = await onScreenshot!(screenshotName, screenshotImage) as bool; + final bool screenshotSuccess = await onScreenshot!(screenshotName, screenshotImage); if (screenshotSuccess) { jsonResponse = await driver.requestData(DriverTestMessage.complete().toString()); } else {