Skip to content

Commit 97e3ba6

Browse files
[various] Fixes unawaited_futures violations (#4067)
This option had been disabled to match flutter/flutter, but the reason it was disabled there was "too many false positives", mostly around animation. That doesn't apply to most packages here, and we've had a number of production bugs�especially in plugins, that use async heavily in ways that are intended to be client-awaitable�that this would have caught. This PR: - Enables the option at the repo level. - Permanently (unless the owners decide to change it) opts out `animations` and `go_router`, both of which looked like mostly or entirely false positives. - Temporarily opted out a few plugins that have a lot of violations that should be handled in their own PRs later (`camera_android_camerax`, most of `webview_flutter`). - Fixes all remaining violations. In many cases this PR is behavior-changing, replacing implicitly unawaited futures that did not seem obviously intentional with `await`ed futures, so non-test code in particular should be reviewed carefully to make sure the changes are correct. All of the changes are manual, not `fix`-generated. Part of flutter/flutter#127323
1 parent f19282a commit 97e3ba6

File tree

78 files changed

+266
-143
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+266
-143
lines changed

analysis_options.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ linter:
183183
- tighten_type_of_initializing_formals
184184
# - type_annotate_public_apis # subset of always_specify_types
185185
- type_init_formals
186-
# - unawaited_futures # too many false positives, especially with the way AnimationController works
186+
- unawaited_futures # DIFFERENT FROM FLUTTER/FLUTTER: It's disabled there for "too many false positives"; that's not an issue here, and missing awaits have caused production issues in plugins.
187187
- unnecessary_await_in_return
188188
- unnecessary_brace_in_string_interps
189189
- unnecessary_const
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# This custom rule set only exists to allow opting out of the repository
2+
# default of enabling unawaited_futures. Please do NOT add more changes
3+
# here without consulting with #hackers-ecosystem on Discord.
4+
5+
include: ../../analysis_options.yaml
6+
7+
linter:
8+
rules:
9+
# Matches flutter/flutter, which disables this rule due to false positives.
10+
unawaited_futures: false

packages/camera/camera/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.10.5+2
2+
3+
* Fixes unawaited_futures violations.
4+
15
## 0.10.5+1
26

37
* Removes obsolete null checks on non-nullable values.

packages/camera/camera/lib/src/camera_controller.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ class CameraController extends ValueNotifier<CameraValue> {
552552
}
553553

554554
if (value.isStreamingImages) {
555-
stopImageStream();
555+
await stopImageStream();
556556
}
557557

558558
try {

packages/camera/camera/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing
44
Dart.
55
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera
66
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
7-
version: 0.10.5+1
7+
version: 0.10.5+2
88

99
environment:
1010
sdk: ">=2.18.0 <4.0.0"

packages/camera/camera/test/camera_image_stream_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ void main() {
174174

175175
await cameraController.initialize();
176176

177-
cameraController.startVideoRecording(
177+
await cameraController.startVideoRecording(
178178
onAvailable: (CameraImage image) => null);
179179

180180
expect(
@@ -192,7 +192,7 @@ void main() {
192192

193193
await cameraController.initialize();
194194

195-
cameraController.startVideoRecording();
195+
await cameraController.startVideoRecording();
196196

197197
expect(mockPlatform.streamCallLog.contains('startVideoCapturing'), isTrue);
198198
});

packages/camera/camera_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## NEXT
2+
3+
* Fixes unawaited_futures violations.
4+
15
## 0.10.8+2
26

37
* Removes obsolete null checks on non-nullable values.

packages/camera/camera_android/example/lib/camera_controller.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,12 @@ class CameraController extends ValueNotifier<CameraValue> {
229229
enableAudio: enableAudio,
230230
);
231231

232-
CameraPlatform.instance
232+
unawaited(CameraPlatform.instance
233233
.onCameraInitialized(_cameraId)
234234
.first
235235
.then((CameraInitializedEvent event) {
236236
initializeCompleter.complete(event);
237-
});
237+
}));
238238

239239
await CameraPlatform.instance.initializeCamera(
240240
_cameraId,
@@ -444,8 +444,8 @@ class CameraController extends ValueNotifier<CameraValue> {
444444
if (_isDisposed) {
445445
return;
446446
}
447-
_deviceOrientationSubscription?.cancel();
448447
_isDisposed = true;
448+
await _deviceOrientationSubscription?.cancel();
449449
super.dispose();
450450
if (_initCalled != null) {
451451
await _initCalled;

packages/camera/camera_android/test/android_camera_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,7 +1119,7 @@ void main() {
11191119
isMethodCall('startImageStream', arguments: null),
11201120
]);
11211121

1122-
subscription.cancel();
1122+
await subscription.cancel();
11231123
});
11241124

11251125
test('Should stop streaming', () async {
@@ -1136,7 +1136,7 @@ void main() {
11361136
final StreamSubscription<CameraImageData> subscription = camera
11371137
.onStreamedFrameAvailable(cameraId)
11381138
.listen((CameraImageData imageData) {});
1139-
subscription.cancel();
1139+
await subscription.cancel();
11401140

11411141
// Assert
11421142
expect(channel.log, <Matcher>[
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# TODO(stuartmorgan): Remove this file and fix all the unawaited_futures
2+
# violations. See https://github.com/flutter/flutter/issues/127323
3+
4+
include: ../../../analysis_options.yaml
5+
6+
linter:
7+
rules:
8+
unawaited_futures: false

packages/camera/camera_avfoundation/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## NEXT
2+
3+
* Fixes unawaited_futures violations.
4+
15
## 0.9.13+2
26

37
* Removes obsolete null checks on non-nullable values.

packages/camera/camera_avfoundation/example/lib/camera_controller.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,12 @@ class CameraController extends ValueNotifier<CameraValue> {
229229
enableAudio: enableAudio,
230230
);
231231

232-
CameraPlatform.instance
232+
unawaited(CameraPlatform.instance
233233
.onCameraInitialized(_cameraId)
234234
.first
235235
.then((CameraInitializedEvent event) {
236236
initializeCompleter.complete(event);
237-
});
237+
}));
238238

239239
await CameraPlatform.instance.initializeCamera(
240240
_cameraId,
@@ -443,8 +443,8 @@ class CameraController extends ValueNotifier<CameraValue> {
443443
if (_isDisposed) {
444444
return;
445445
}
446-
_deviceOrientationSubscription?.cancel();
447446
_isDisposed = true;
447+
await _deviceOrientationSubscription?.cancel();
448448
super.dispose();
449449
if (_initCalled != null) {
450450
await _initCalled;

packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,7 @@ void main() {
11201120
isMethodCall('startImageStream', arguments: null),
11211121
]);
11221122

1123-
subscription.cancel();
1123+
await subscription.cancel();
11241124
});
11251125

11261126
test('Should stop streaming', () async {
@@ -1137,7 +1137,7 @@ void main() {
11371137
final StreamSubscription<CameraImageData> subscription = camera
11381138
.onStreamedFrameAvailable(cameraId)
11391139
.listen((CameraImageData imageData) {});
1140-
subscription.cancel();
1140+
await subscription.cancel();
11411141

11421142
// Assert
11431143
expect(channel.log, <Matcher>[

packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,7 @@ void main() {
10851085
isMethodCall('startImageStream', arguments: null),
10861086
]);
10871087

1088-
subscription.cancel();
1088+
await subscription.cancel();
10891089
});
10901090

10911091
test('Should stop streaming', () async {
@@ -1102,7 +1102,7 @@ void main() {
11021102
final StreamSubscription<CameraImageData> subscription = camera
11031103
.onStreamedFrameAvailable(cameraId)
11041104
.listen((CameraImageData imageData) {});
1105-
subscription.cancel();
1105+
await subscription.cancel();
11061106

11071107
// Assert
11081108
expect(channel.log, <Matcher>[

packages/camera/camera_windows/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 0.2.1+7
22

3+
* Fixes unawaited_futures violations.
34
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
45

56
## 0.2.1+6

packages/camera/camera_windows/example/lib/main.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ class _MyAppState extends State<MyApp> {
9999
enableAudio: _recordAudio,
100100
);
101101

102-
_errorStreamSubscription?.cancel();
102+
unawaited(_errorStreamSubscription?.cancel());
103103
_errorStreamSubscription = CameraPlatform.instance
104104
.onCameraError(cameraId)
105105
.listen(_onCameraError);
106106

107-
_cameraClosingStreamSubscription?.cancel();
107+
unawaited(_cameraClosingStreamSubscription?.cancel());
108108
_cameraClosingStreamSubscription = CameraPlatform.instance
109109
.onCameraClosing(cameraId)
110110
.listen(_onCameraClosing);
@@ -193,7 +193,7 @@ class _MyAppState extends State<MyApp> {
193193

194194
Future<void> _recordTimed(int seconds) async {
195195
if (_initialized && _cameraId > 0 && !_recordingTimed) {
196-
CameraPlatform.instance
196+
unawaited(CameraPlatform.instance
197197
.onVideoRecordedEvent(_cameraId)
198198
.first
199199
.then((VideoRecordedEvent event) async {
@@ -204,7 +204,7 @@ class _MyAppState extends State<MyApp> {
204204

205205
_showInSnackBar('Video captured to: ${event.file.path}');
206206
}
207-
});
207+
}));
208208

209209
await CameraPlatform.instance.startVideoRecording(
210210
_cameraId,

packages/camera/camera_windows/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: camera_windows
22
description: A Flutter plugin for getting information about and controlling the camera on Windows.
33
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_windows
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
5-
version: 0.2.1+6
5+
version: 0.2.1+7
66

77
environment:
88
sdk: ">=2.18.0 <4.0.0"

packages/cross_file/tool/run_tests.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//
99
// usage: dart run tool/run_tests.dart
1010
// (needs a `chrome` executable in $PATH, or a tweak to dart_test.yaml)
11+
import 'dart:async';
1112
import 'dart:io';
1213
import 'package:path/path.dart' as p;
1314

@@ -30,8 +31,8 @@ Future<void> main(List<String> args) async {
3031

3132
Future<Process> _streamOutput(Future<Process> processFuture) async {
3233
final Process process = await processFuture;
33-
stdout.addStream(process.stdout);
34-
stderr.addStream(process.stderr);
34+
unawaited(stdout.addStream(process.stdout));
35+
unawaited(stderr.addStream(process.stderr));
3536
return process;
3637
}
3738

packages/flutter_image/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 4.1.6
22

3+
* Fixes unawaited_futures violations.
34
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
45
* Aligns Dart and Flutter SDK constraints.
56

packages/flutter_image/lib/network.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ class NetworkImageWithRetry extends ImageProvider<NetworkImageWithRetry> {
191191
scale: key.scale,
192192
);
193193
} catch (error) {
194-
request?.close();
194+
await request?.close();
195195
lastFailure = error is FetchFailure
196196
? error
197197
: FetchFailure._(

packages/flutter_image/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: >
33
Image utilities for Flutter: improved network providers, effects, etc.
44
repository: https://github.com/flutter/packages/tree/main/packages/flutter_image
55
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_image%22
6-
version: 4.1.5
6+
version: 4.1.6
77

88
environment:
99
sdk: ">=2.18.0 <4.0.0"

packages/flutter_markdown/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## NEXT
22

3+
* Fixes unawaited_futures violations.
34
* Updates minimum Flutter version to 3.3.
45
* Aligns Dart and Flutter SDK constraints.
56
* Replace `describeEnum` with the `name` getter.

packages/flutter_markdown/example/lib/demos/basic_markdown_demo.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:async';
6+
57
import 'package:flutter/material.dart';
68
import 'package:flutter/services.dart';
79
import 'package:flutter_markdown/flutter_markdown.dart';
@@ -125,11 +127,11 @@ class _BasicMarkdownDemoState extends State<BasicMarkdownDemo> {
125127
String? href,
126128
String title,
127129
) async {
128-
showDialog<Widget>(
130+
unawaited(showDialog<Widget>(
129131
context: context,
130132
builder: (BuildContext context) =>
131133
_createDialog(context, text, href, title),
132-
);
134+
));
133135
}
134136

135137
Widget _createDialog(

packages/flutter_markdown/example/lib/screens/demo_screen.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class DemoNotesView extends StatelessWidget {
109109
String? href,
110110
String title,
111111
) async {
112-
showDialog<Widget>(
112+
await showDialog<Widget>(
113113
context: context,
114114
builder: (BuildContext context) =>
115115
_createDialog(context, text, href, title),
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
# This custom rule set only exists to allow very targeted changes
2+
# relative to the default repo settings, for specific use cases.
3+
# Please do NOT add more changes here without consulting with
4+
# #hackers-ecosystem on Discord.
5+
16
include: ../../analysis_options.yaml
27

38
analyzer:
49
exclude:
10+
# This directory deliberately has errors, to test `fix`.
511
- "test_fixes/**"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# This custom rule set only exists to allow very targeted changes
2+
# relative to the default repo settings, for specific use cases.
3+
# Please do NOT add more changes here without consulting with
4+
# #hackers-ecosystem on Discord.
5+
6+
include: ../../../analysis_options.yaml
7+
8+
linter:
9+
rules:
10+
# Matches flutter/flutter, which disables this rule due to false positives
11+
# from navigator APIs.
12+
unawaited_futures: false

packages/go_router/test/go_router_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
// ignore_for_file: cascade_invocations, diagnostic_describe_all_properties
5+
// ignore_for_file: cascade_invocations, diagnostic_describe_all_properties, unawaited_futures
66

77
import 'dart:async';
88

packages/go_router/tool/run_tests.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
// ignore_for_file: avoid_print
1010

11+
import 'dart:async';
1112
import 'dart:io';
1213
import 'package:io/io.dart' as io;
1314
import 'package:path/path.dart' as p;
@@ -99,8 +100,8 @@ dependencies:
99100

100101
Future<Process> _streamOutput(Future<Process> processFuture) async {
101102
final Process process = await processFuture;
102-
stdout.addStream(process.stdout);
103-
stderr.addStream(process.stderr);
103+
unawaited(stdout.addStream(process.stdout));
104+
unawaited(stderr.addStream(process.stderr));
104105
return process;
105106
}
106107

packages/go_router_builder/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 2.0.2
22

3+
* Fixes unawaited_futures violations.
34
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
45

56
## 2.0.1

0 commit comments

Comments
 (0)