From 7223169fabe41d81364c320a7f12bf9f3f9e64ef Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 21 Oct 2024 17:02:36 +0000 Subject: [PATCH 01/12] Enable avoid_dynamic_calls lint Add argument types to `typedMatches` arguments which were unnecessarily widening it back to `dynamic`. Add some missing `as dynamic` and `as Function` which is the pattern the lint uses to allow intentional dynamic calls. Ignore some dynamic calls in a test for a legacy API. Ignore a couple false positives for calling methods (as opposed to getters) on a cast expression. The false positive was fixed in https://dart-review.googlesource.com/c/sdk/+/390640 but not yet published. Replaces https://github.com/dart-lang/matcher/pull/205 --- pkgs/matcher/CHANGELOG.md | 4 ++++ pkgs/matcher/analysis_options.yaml | 1 + pkgs/matcher/lib/src/core_matchers.dart | 2 +- pkgs/matcher/lib/src/expect/throws_matcher.dart | 2 +- pkgs/matcher/lib/src/iterable_matchers.dart | 2 +- pkgs/matcher/lib/src/map_matchers.dart | 9 ++++++--- pkgs/matcher/lib/src/numeric_matchers.dart | 6 +++--- pkgs/matcher/lib/src/operator_matchers.dart | 2 +- pkgs/matcher/lib/src/order_matchers.dart | 2 +- pkgs/matcher/lib/src/string_matchers.dart | 6 +++--- pkgs/matcher/pubspec.yaml | 2 +- pkgs/matcher/test/expect_async_test.dart | 8 ++++---- pkgs/matcher/test/matcher/throws_type_test.dart | 1 + 13 files changed, 28 insertions(+), 19 deletions(-) diff --git a/pkgs/matcher/CHANGELOG.md b/pkgs/matcher/CHANGELOG.md index 1ec153e47..f010d1fcf 100644 --- a/pkgs/matcher/CHANGELOG.md +++ b/pkgs/matcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.12.18-wip + +* Remove some dynamic invocation. + ## 0.12.17 * Require Dart 3.4 diff --git a/pkgs/matcher/analysis_options.yaml b/pkgs/matcher/analysis_options.yaml index f0f137ff3..93d003694 100644 --- a/pkgs/matcher/analysis_options.yaml +++ b/pkgs/matcher/analysis_options.yaml @@ -3,6 +3,7 @@ include: package:lints/recommended.yaml linter: rules: - always_declare_return_types + - avoid_dynamic_calls - avoid_private_typedef_functions - avoid_unused_constructor_parameters - cancel_subscriptions diff --git a/pkgs/matcher/lib/src/core_matchers.dart b/pkgs/matcher/lib/src/core_matchers.dart index 70e34491d..1fc48edad 100644 --- a/pkgs/matcher/lib/src/core_matchers.dart +++ b/pkgs/matcher/lib/src/core_matchers.dart @@ -148,7 +148,7 @@ class _ReturnsNormally extends FeatureMatcher { const _ReturnsNormally(); @override - bool typedMatches(Function f, Map matchState) { + bool typedMatches(void Function() f, Map matchState) { try { f(); return true; diff --git a/pkgs/matcher/lib/src/expect/throws_matcher.dart b/pkgs/matcher/lib/src/expect/throws_matcher.dart index 3a8182131..cae1ce050 100644 --- a/pkgs/matcher/lib/src/expect/throws_matcher.dart +++ b/pkgs/matcher/lib/src/expect/throws_matcher.dart @@ -83,7 +83,7 @@ class Throws extends AsyncMatcher { try { item as Function; - var value = item(); + var value = (item as Function)(); if (value is Future) { return _matchFuture(value, 'returned a Future that emitted '); } diff --git a/pkgs/matcher/lib/src/iterable_matchers.dart b/pkgs/matcher/lib/src/iterable_matchers.dart index 918650a26..abc9688e8 100644 --- a/pkgs/matcher/lib/src/iterable_matchers.dart +++ b/pkgs/matcher/lib/src/iterable_matchers.dart @@ -204,7 +204,7 @@ class _UnorderedMatches extends _IterableMatcher { .add(' unordered'); @override - Description describeTypedMismatch(dynamic item, + Description describeTypedMismatch(Iterable item, Description mismatchDescription, Map matchState, bool verbose) => mismatchDescription.add(_test(item.toList())!); diff --git a/pkgs/matcher/lib/src/map_matchers.dart b/pkgs/matcher/lib/src/map_matchers.dart index 97be1ea7d..4476d0637 100644 --- a/pkgs/matcher/lib/src/map_matchers.dart +++ b/pkgs/matcher/lib/src/map_matchers.dart @@ -15,6 +15,7 @@ class _ContainsValue extends Matcher { @override bool matches(Object? item, Map matchState) => + // ignore: avoid_dynamic_calls (item as dynamic).containsValue(_value); @override Description describe(Description description) => @@ -34,8 +35,9 @@ class _ContainsMapping extends Matcher { @override bool matches(Object? item, Map matchState) => + // ignore: avoid_dynamic_calls (item as dynamic).containsKey(_key) && - _valueMatcher.matches(item[_key], matchState); + _valueMatcher.matches((item as dynamic)[_key], matchState); @override Description describe(Description description) { @@ -49,7 +51,8 @@ class _ContainsMapping extends Matcher { @override Description describeMismatch(Object? item, Description mismatchDescription, Map matchState, bool verbose) { - if (!(item as dynamic).containsKey(_key)) { + // ignore: avoid_dynamic_calls + if (!((item as dynamic).containsKey(_key) as bool)) { return mismatchDescription .add(" doesn't contain key ") .addDescriptionOf(_key); @@ -59,7 +62,7 @@ class _ContainsMapping extends Matcher { .addDescriptionOf(_key) .add(' but with value '); _valueMatcher.describeMismatch( - item[_key], mismatchDescription, matchState, verbose); + (item as dynamic)[_key], mismatchDescription, matchState, verbose); return mismatchDescription; } } diff --git a/pkgs/matcher/lib/src/numeric_matchers.dart b/pkgs/matcher/lib/src/numeric_matchers.dart index 5193d302e..fd3e21ece 100644 --- a/pkgs/matcher/lib/src/numeric_matchers.dart +++ b/pkgs/matcher/lib/src/numeric_matchers.dart @@ -18,7 +18,7 @@ class _IsCloseTo extends FeatureMatcher { const _IsCloseTo(this._value, this._delta); @override - bool typedMatches(dynamic item, Map matchState) { + bool typedMatches(num item, Map matchState) { var diff = item - _value; if (diff < 0) diff = -diff; return diff <= _delta; @@ -32,7 +32,7 @@ class _IsCloseTo extends FeatureMatcher { .addDescriptionOf(_value); @override - Description describeTypedMismatch(dynamic item, + Description describeTypedMismatch(num item, Description mismatchDescription, Map matchState, bool verbose) { var diff = item - _value; if (diff < 0) diff = -diff; @@ -67,7 +67,7 @@ class _InRange extends FeatureMatcher { this._low, this._high, this._lowMatchValue, this._highMatchValue); @override - bool typedMatches(dynamic value, Map matchState) { + bool typedMatches(num value, Map matchState) { if (value < _low || value > _high) { return false; } diff --git a/pkgs/matcher/lib/src/operator_matchers.dart b/pkgs/matcher/lib/src/operator_matchers.dart index ced25fcd7..15e50ffca 100644 --- a/pkgs/matcher/lib/src/operator_matchers.dart +++ b/pkgs/matcher/lib/src/operator_matchers.dart @@ -57,7 +57,7 @@ class _AllOf extends Matcher { @override Description describeMismatch(dynamic item, Description mismatchDescription, Map matchState, bool verbose) { - var matcher = matchState['matcher']; + var matcher = matchState['matcher'] as Matcher; matcher.describeMismatch( item, mismatchDescription, matchState['state'], verbose); return mismatchDescription; diff --git a/pkgs/matcher/lib/src/order_matchers.dart b/pkgs/matcher/lib/src/order_matchers.dart index 1146f6ab2..6fe7c76d4 100644 --- a/pkgs/matcher/lib/src/order_matchers.dart +++ b/pkgs/matcher/lib/src/order_matchers.dart @@ -80,7 +80,7 @@ class _OrderingMatcher extends Matcher { return _equalValue; } else if ((item as dynamic) < _value) { return _lessThanValue; - } else if (item > _value) { + } else if ((item as dynamic) > _value) { return _greaterThanValue; } else { return false; diff --git a/pkgs/matcher/lib/src/string_matchers.dart b/pkgs/matcher/lib/src/string_matchers.dart index 8b2f95ae1..b819fa5a5 100644 --- a/pkgs/matcher/lib/src/string_matchers.dart +++ b/pkgs/matcher/lib/src/string_matchers.dart @@ -80,7 +80,7 @@ class _StringStartsWith extends FeatureMatcher { const _StringStartsWith(this._prefix); @override - bool typedMatches(dynamic item, Map matchState) => item.startsWith(_prefix); + bool typedMatches(String item, Map matchState) => item.startsWith(_prefix); @override Description describe(Description description) => @@ -97,7 +97,7 @@ class _StringEndsWith extends FeatureMatcher { const _StringEndsWith(this._suffix); @override - bool typedMatches(dynamic item, Map matchState) => item.endsWith(_suffix); + bool typedMatches(String item, Map matchState) => item.endsWith(_suffix); @override Description describe(Description description) => @@ -119,7 +119,7 @@ class _StringContainsInOrder extends FeatureMatcher { const _StringContainsInOrder(this._substrings); @override - bool typedMatches(dynamic item, Map matchState) { + bool typedMatches(String item, Map matchState) { var fromIndex = 0; for (var s in _substrings) { var index = item.indexOf(s, fromIndex); diff --git a/pkgs/matcher/pubspec.yaml b/pkgs/matcher/pubspec.yaml index 291b3e9b4..237e5593e 100644 --- a/pkgs/matcher/pubspec.yaml +++ b/pkgs/matcher/pubspec.yaml @@ -1,5 +1,5 @@ name: matcher -version: 0.12.17 +version: 0.12.18-wip description: >- Support for specifying test expectations via an extensible Matcher class. Also includes a number of built-in Matcher implementations for common cases. diff --git a/pkgs/matcher/test/expect_async_test.dart b/pkgs/matcher/test/expect_async_test.dart index dd564ea5c..7619893b7 100644 --- a/pkgs/matcher/test/expect_async_test.dart +++ b/pkgs/matcher/test/expect_async_test.dart @@ -336,7 +336,7 @@ void main() { test('works with no arguments', () async { var callbackRun = false; var monitor = await TestCaseMonitor.run(() { - // ignore: deprecated_member_use_from_same_package + // ignore: deprecated_member_use_from_same_package, avoid_dynamic_calls expectAsync(() { callbackRun = true; })(); @@ -349,7 +349,7 @@ void main() { test('works with dynamic arguments', () async { var callbackRun = false; var monitor = await TestCaseMonitor.run(() { - // ignore: deprecated_member_use_from_same_package + // ignore: deprecated_member_use_from_same_package, avoid_dynamic_calls expectAsync((arg1, arg2) { callbackRun = true; })(1, 2); @@ -362,7 +362,7 @@ void main() { test('works with non-nullable arguments', () async { var callbackRun = false; var monitor = await TestCaseMonitor.run(() { - // ignore: deprecated_member_use_from_same_package + // ignore: deprecated_member_use_from_same_package, avoid_dynamic_calls expectAsync((int arg1, int arg2) { callbackRun = true; })(1, 2); @@ -375,7 +375,7 @@ void main() { test('works with 6 arguments', () async { var callbackRun = false; var monitor = await TestCaseMonitor.run(() { - // ignore: deprecated_member_use_from_same_package + // ignore: deprecated_member_use_from_same_package, avoid_dynamic_calls expectAsync((arg1, arg2, arg3, arg4, arg5, arg6) { callbackRun = true; })(1, 2, 3, 4, 5, 6); diff --git a/pkgs/matcher/test/matcher/throws_type_test.dart b/pkgs/matcher/test/matcher/throws_type_test.dart index f4c55b014..557a73aac 100644 --- a/pkgs/matcher/test/matcher/throws_type_test.dart +++ b/pkgs/matcher/test/matcher/throws_type_test.dart @@ -95,6 +95,7 @@ void main() { group('[throwsNoSuchMethodError]', () { test('passes when a NoSuchMethodError is thrown', () { expect(() { + // ignore: avoid_dynamic_calls (1 as dynamic).notAMethodOnInt(); }, throwsNoSuchMethodError); }); From a459dce7cb51838ea3c05ace11d9394122becc65 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 21 Oct 2024 21:45:33 +0000 Subject: [PATCH 02/12] Change to a more specific cast instead of using a dynamic call --- pkgs/matcher/lib/src/expect/throws_matcher.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/matcher/lib/src/expect/throws_matcher.dart b/pkgs/matcher/lib/src/expect/throws_matcher.dart index cae1ce050..88be14e32 100644 --- a/pkgs/matcher/lib/src/expect/throws_matcher.dart +++ b/pkgs/matcher/lib/src/expect/throws_matcher.dart @@ -82,8 +82,8 @@ class Throws extends AsyncMatcher { } try { - item as Function; - var value = (item as Function)(); + item as Object? Function(); + var value = item(); if (value is Future) { return _matchFuture(value, 'returned a Future that emitted '); } From 7f2be62e84eafa32411793752133a70acdc281be Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 21 Oct 2024 21:48:45 +0000 Subject: [PATCH 03/12] Use a more specific function type for a `FeatureMatcher` generic. --- pkgs/matcher/lib/src/core_matchers.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/matcher/lib/src/core_matchers.dart b/pkgs/matcher/lib/src/core_matchers.dart index 1fc48edad..09230fa08 100644 --- a/pkgs/matcher/lib/src/core_matchers.dart +++ b/pkgs/matcher/lib/src/core_matchers.dart @@ -144,7 +144,7 @@ class isInstanceOf extends TypeMatcher { /// a wrapper will have to be created. const Matcher returnsNormally = _ReturnsNormally(); -class _ReturnsNormally extends FeatureMatcher { +class _ReturnsNormally extends FeatureMatcher { const _ReturnsNormally(); @override From 077accff7c48d9af57007e1a0608e78fdc3ded9d Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 21 Oct 2024 21:53:21 +0000 Subject: [PATCH 04/12] format --- pkgs/matcher/lib/src/numeric_matchers.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/matcher/lib/src/numeric_matchers.dart b/pkgs/matcher/lib/src/numeric_matchers.dart index fd3e21ece..a7981609e 100644 --- a/pkgs/matcher/lib/src/numeric_matchers.dart +++ b/pkgs/matcher/lib/src/numeric_matchers.dart @@ -32,8 +32,8 @@ class _IsCloseTo extends FeatureMatcher { .addDescriptionOf(_value); @override - Description describeTypedMismatch(num item, - Description mismatchDescription, Map matchState, bool verbose) { + Description describeTypedMismatch( + num item, Description mismatchDescription, Map matchState, bool verbose) { var diff = item - _value; if (diff < 0) diff = -diff; return mismatchDescription.add(' differs by ').addDescriptionOf(diff); From 8d0a7a850048c97e5673356c36499e9f04a0100b Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 21 Oct 2024 22:18:40 +0000 Subject: [PATCH 05/12] Back as a cast --- pkgs/matcher/lib/src/expect/throws_matcher.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkgs/matcher/lib/src/expect/throws_matcher.dart b/pkgs/matcher/lib/src/expect/throws_matcher.dart index 88be14e32..37676ef72 100644 --- a/pkgs/matcher/lib/src/expect/throws_matcher.dart +++ b/pkgs/matcher/lib/src/expect/throws_matcher.dart @@ -82,8 +82,7 @@ class Throws extends AsyncMatcher { } try { - item as Object? Function(); - var value = item(); + var value = (item as Function)(); if (value is Future) { return _matchFuture(value, 'returned a Future that emitted '); } From 7b3d0ded5a4d7f1b597407e92dfb0fe5ca01a6a8 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 21 Oct 2024 22:19:10 +0000 Subject: [PATCH 06/12] Cleanup: Add a library directive for a test annotaiton --- pkgs/matcher/test/mirror_matchers_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/matcher/test/mirror_matchers_test.dart b/pkgs/matcher/test/mirror_matchers_test.dart index b19fe3ea6..06f0df411 100644 --- a/pkgs/matcher/test/mirror_matchers_test.dart +++ b/pkgs/matcher/test/mirror_matchers_test.dart @@ -5,6 +5,7 @@ // ignore_for_file: deprecated_member_use_from_same_package @TestOn('vm') +library; import 'package:matcher/mirror_matchers.dart'; import 'package:test/test.dart'; From 204d4c3cc67ea3138e6a08f95e8ac2c0be461bc9 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 21 Oct 2024 22:36:34 +0000 Subject: [PATCH 07/12] Use an intentional type widening to allow the cast --- pkgs/matcher/lib/src/core_matchers.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/matcher/lib/src/core_matchers.dart b/pkgs/matcher/lib/src/core_matchers.dart index 09230fa08..f96bc6284 100644 --- a/pkgs/matcher/lib/src/core_matchers.dart +++ b/pkgs/matcher/lib/src/core_matchers.dart @@ -144,13 +144,13 @@ class isInstanceOf extends TypeMatcher { /// a wrapper will have to be created. const Matcher returnsNormally = _ReturnsNormally(); -class _ReturnsNormally extends FeatureMatcher { +class _ReturnsNormally extends FeatureMatcher { const _ReturnsNormally(); @override - bool typedMatches(void Function() f, Map matchState) { + bool typedMatches(Object f, Map matchState) { try { - f(); + (f as Function)(); return true; } catch (e, s) { addStateInfo(matchState, {'exception': e, 'stack': s}); From be5509d94b90eb0dedb38a951240c7611fe6c469 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Oct 2024 18:11:10 +0000 Subject: [PATCH 08/12] Ignore a cast instead of loosening type --- pkgs/matcher/lib/src/core_matchers.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/matcher/lib/src/core_matchers.dart b/pkgs/matcher/lib/src/core_matchers.dart index f96bc6284..afb835b09 100644 --- a/pkgs/matcher/lib/src/core_matchers.dart +++ b/pkgs/matcher/lib/src/core_matchers.dart @@ -148,8 +148,9 @@ class _ReturnsNormally extends FeatureMatcher { const _ReturnsNormally(); @override - bool typedMatches(Object f, Map matchState) { + bool typedMatches(Function f, Map matchState) { try { + // ignore: unnecessary_cast (f as Function)(); return true; } catch (e, s) { From 563608f62357b3abfcf7834f5bf6eb65f61cb440 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Oct 2024 18:13:50 +0000 Subject: [PATCH 09/12] Remove a deprecated lint rule --- pkgs/matcher/analysis_options.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/matcher/analysis_options.yaml b/pkgs/matcher/analysis_options.yaml index 93d003694..d183f7bb3 100644 --- a/pkgs/matcher/analysis_options.yaml +++ b/pkgs/matcher/analysis_options.yaml @@ -16,7 +16,6 @@ linter: - no_runtimeType_toString - omit_local_variable_types - only_throw_errors - - package_api_docs - prefer_const_constructors - prefer_relative_imports - prefer_single_quotes From cd007cc4f65bb00c4c6204e162ca93483650f186 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Oct 2024 18:21:31 +0000 Subject: [PATCH 10/12] Another pacakge_api_docs Unblocking CI, will submit these changes separately in https://github.com/dart-lang/test/pull/2411 --- pkgs/fake_async/analysis_options.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/fake_async/analysis_options.yaml b/pkgs/fake_async/analysis_options.yaml index c0b72ff33..4e1b8e86f 100644 --- a/pkgs/fake_async/analysis_options.yaml +++ b/pkgs/fake_async/analysis_options.yaml @@ -15,7 +15,6 @@ linter: - join_return_with_assignment - literal_only_boolean_expressions - no_adjacent_strings_in_list - - package_api_docs - prefer_const_constructors - prefer_final_locals - test_types_in_equals From ab8f6596ce7a31ff5c55bca59c0c961b53f22e0a Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Oct 2024 19:40:32 +0000 Subject: [PATCH 11/12] Typo in changelog --- pkgs/matcher/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/matcher/CHANGELOG.md b/pkgs/matcher/CHANGELOG.md index f010d1fcf..0522c4cee 100644 --- a/pkgs/matcher/CHANGELOG.md +++ b/pkgs/matcher/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.12.18-wip -* Remove some dynamic invocation. +* Remove some dynamic invocations. ## 0.12.17 From c5fbf3104299af711a3fe141139f4a7704faa5e1 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Fri, 25 Oct 2024 00:10:34 +0000 Subject: [PATCH 12/12] Use FeatureMatcher for containsKey and containsValue --- pkgs/matcher/lib/src/map_matchers.dart | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/pkgs/matcher/lib/src/map_matchers.dart b/pkgs/matcher/lib/src/map_matchers.dart index 4476d0637..5328b88b9 100644 --- a/pkgs/matcher/lib/src/map_matchers.dart +++ b/pkgs/matcher/lib/src/map_matchers.dart @@ -2,21 +2,20 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'feature_matcher.dart'; import 'interfaces.dart'; import 'util.dart'; /// Returns a matcher which matches maps containing the given [value]. Matcher containsValue(Object? value) => _ContainsValue(value); -class _ContainsValue extends Matcher { +class _ContainsValue extends FeatureMatcher { final Object? _value; const _ContainsValue(this._value); @override - bool matches(Object? item, Map matchState) => - // ignore: avoid_dynamic_calls - (item as dynamic).containsValue(_value); + bool typedMatches(Map item, Map matchState) => item.containsValue(_value); @override Description describe(Description description) => description.add('contains value ').addDescriptionOf(_value); @@ -27,17 +26,15 @@ class _ContainsValue extends Matcher { Matcher containsPair(Object? key, Object? valueOrMatcher) => _ContainsMapping(key, wrapMatcher(valueOrMatcher)); -class _ContainsMapping extends Matcher { +class _ContainsMapping extends FeatureMatcher { final Object? _key; final Matcher _valueMatcher; const _ContainsMapping(this._key, this._valueMatcher); @override - bool matches(Object? item, Map matchState) => - // ignore: avoid_dynamic_calls - (item as dynamic).containsKey(_key) && - _valueMatcher.matches((item as dynamic)[_key], matchState); + bool typedMatches(Map item, Map matchState) => + item.containsKey(_key) && _valueMatcher.matches(item[_key], matchState); @override Description describe(Description description) { @@ -49,10 +46,9 @@ class _ContainsMapping extends Matcher { } @override - Description describeMismatch(Object? item, Description mismatchDescription, - Map matchState, bool verbose) { - // ignore: avoid_dynamic_calls - if (!((item as dynamic).containsKey(_key) as bool)) { + Description describeTypedMismatch( + Map item, Description mismatchDescription, Map matchState, bool verbose) { + if (!item.containsKey(_key)) { return mismatchDescription .add(" doesn't contain key ") .addDescriptionOf(_key); @@ -62,7 +58,7 @@ class _ContainsMapping extends Matcher { .addDescriptionOf(_key) .add(' but with value '); _valueMatcher.describeMismatch( - (item as dynamic)[_key], mismatchDescription, matchState, verbose); + item[_key], mismatchDescription, matchState, verbose); return mismatchDescription; } }