[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 https://github.com/flutter/flutter/issues/127323
This commit is contained in:
stuartmorgan
2023-05-24 08:39:26 -07:00
committed by GitHub
parent f19282ab42
commit 97e3ba64d7
78 changed files with 266 additions and 143 deletions

View File

@ -183,7 +183,7 @@ linter:
- tighten_type_of_initializing_formals
# - type_annotate_public_apis # subset of always_specify_types
- type_init_formals
# - unawaited_futures # too many false positives, especially with the way AnimationController works
- 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.
- unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- unnecessary_const

View File

@ -0,0 +1,10 @@
# This custom rule set only exists to allow opting out of the repository
# default of enabling unawaited_futures. Please do NOT add more changes
# here without consulting with #hackers-ecosystem on Discord.
include: ../../analysis_options.yaml
linter:
rules:
# Matches flutter/flutter, which disables this rule due to false positives.
unawaited_futures: false

View File

@ -1,3 +1,7 @@
## 0.10.5+2
* Fixes unawaited_futures violations.
## 0.10.5+1
* Removes obsolete null checks on non-nullable values.

View File

@ -552,7 +552,7 @@ class CameraController extends ValueNotifier<CameraValue> {
}
if (value.isStreamingImages) {
stopImageStream();
await stopImageStream();
}
try {

View File

@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing
Dart.
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
version: 0.10.5+1
version: 0.10.5+2
environment:
sdk: ">=2.18.0 <4.0.0"

View File

@ -174,7 +174,7 @@ void main() {
await cameraController.initialize();
cameraController.startVideoRecording(
await cameraController.startVideoRecording(
onAvailable: (CameraImage image) => null);
expect(
@ -192,7 +192,7 @@ void main() {
await cameraController.initialize();
cameraController.startVideoRecording();
await cameraController.startVideoRecording();
expect(mockPlatform.streamCallLog.contains('startVideoCapturing'), isTrue);
});

View File

@ -1,3 +1,7 @@
## NEXT
* Fixes unawaited_futures violations.
## 0.10.8+2
* Removes obsolete null checks on non-nullable values.

View File

@ -229,12 +229,12 @@ class CameraController extends ValueNotifier<CameraValue> {
enableAudio: enableAudio,
);
CameraPlatform.instance
unawaited(CameraPlatform.instance
.onCameraInitialized(_cameraId)
.first
.then((CameraInitializedEvent event) {
initializeCompleter.complete(event);
});
}));
await CameraPlatform.instance.initializeCamera(
_cameraId,
@ -444,8 +444,8 @@ class CameraController extends ValueNotifier<CameraValue> {
if (_isDisposed) {
return;
}
_deviceOrientationSubscription?.cancel();
_isDisposed = true;
await _deviceOrientationSubscription?.cancel();
super.dispose();
if (_initCalled != null) {
await _initCalled;

View File

@ -1119,7 +1119,7 @@ void main() {
isMethodCall('startImageStream', arguments: null),
]);
subscription.cancel();
await subscription.cancel();
});
test('Should stop streaming', () async {
@ -1136,7 +1136,7 @@ void main() {
final StreamSubscription<CameraImageData> subscription = camera
.onStreamedFrameAvailable(cameraId)
.listen((CameraImageData imageData) {});
subscription.cancel();
await subscription.cancel();
// Assert
expect(channel.log, <Matcher>[

View File

@ -0,0 +1,8 @@
# TODO(stuartmorgan): Remove this file and fix all the unawaited_futures
# violations. See https://github.com/flutter/flutter/issues/127323
include: ../../../analysis_options.yaml
linter:
rules:
unawaited_futures: false

View File

@ -1,3 +1,7 @@
## NEXT
* Fixes unawaited_futures violations.
## 0.9.13+2
* Removes obsolete null checks on non-nullable values.

View File

@ -229,12 +229,12 @@ class CameraController extends ValueNotifier<CameraValue> {
enableAudio: enableAudio,
);
CameraPlatform.instance
unawaited(CameraPlatform.instance
.onCameraInitialized(_cameraId)
.first
.then((CameraInitializedEvent event) {
initializeCompleter.complete(event);
});
}));
await CameraPlatform.instance.initializeCamera(
_cameraId,
@ -443,8 +443,8 @@ class CameraController extends ValueNotifier<CameraValue> {
if (_isDisposed) {
return;
}
_deviceOrientationSubscription?.cancel();
_isDisposed = true;
await _deviceOrientationSubscription?.cancel();
super.dispose();
if (_initCalled != null) {
await _initCalled;

View File

@ -1120,7 +1120,7 @@ void main() {
isMethodCall('startImageStream', arguments: null),
]);
subscription.cancel();
await subscription.cancel();
});
test('Should stop streaming', () async {
@ -1137,7 +1137,7 @@ void main() {
final StreamSubscription<CameraImageData> subscription = camera
.onStreamedFrameAvailable(cameraId)
.listen((CameraImageData imageData) {});
subscription.cancel();
await subscription.cancel();
// Assert
expect(channel.log, <Matcher>[

View File

@ -1085,7 +1085,7 @@ void main() {
isMethodCall('startImageStream', arguments: null),
]);
subscription.cancel();
await subscription.cancel();
});
test('Should stop streaming', () async {
@ -1102,7 +1102,7 @@ void main() {
final StreamSubscription<CameraImageData> subscription = camera
.onStreamedFrameAvailable(cameraId)
.listen((CameraImageData imageData) {});
subscription.cancel();
await subscription.cancel();
// Assert
expect(channel.log, <Matcher>[

View File

@ -1,5 +1,6 @@
## NEXT
## 0.2.1+7
* Fixes unawaited_futures violations.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
## 0.2.1+6

View File

@ -99,12 +99,12 @@ class _MyAppState extends State<MyApp> {
enableAudio: _recordAudio,
);
_errorStreamSubscription?.cancel();
unawaited(_errorStreamSubscription?.cancel());
_errorStreamSubscription = CameraPlatform.instance
.onCameraError(cameraId)
.listen(_onCameraError);
_cameraClosingStreamSubscription?.cancel();
unawaited(_cameraClosingStreamSubscription?.cancel());
_cameraClosingStreamSubscription = CameraPlatform.instance
.onCameraClosing(cameraId)
.listen(_onCameraClosing);
@ -193,7 +193,7 @@ class _MyAppState extends State<MyApp> {
Future<void> _recordTimed(int seconds) async {
if (_initialized && _cameraId > 0 && !_recordingTimed) {
CameraPlatform.instance
unawaited(CameraPlatform.instance
.onVideoRecordedEvent(_cameraId)
.first
.then((VideoRecordedEvent event) async {
@ -204,7 +204,7 @@ class _MyAppState extends State<MyApp> {
_showInSnackBar('Video captured to: ${event.file.path}');
}
});
}));
await CameraPlatform.instance.startVideoRecording(
_cameraId,

View File

@ -2,7 +2,7 @@ name: camera_windows
description: A Flutter plugin for getting information about and controlling the camera on Windows.
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_windows
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
version: 0.2.1+6
version: 0.2.1+7
environment:
sdk: ">=2.18.0 <4.0.0"

View File

@ -8,6 +8,7 @@
//
// usage: dart run tool/run_tests.dart
// (needs a `chrome` executable in $PATH, or a tweak to dart_test.yaml)
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as p;
@ -30,8 +31,8 @@ Future<void> main(List<String> args) async {
Future<Process> _streamOutput(Future<Process> processFuture) async {
final Process process = await processFuture;
stdout.addStream(process.stdout);
stderr.addStream(process.stderr);
unawaited(stdout.addStream(process.stdout));
unawaited(stderr.addStream(process.stderr));
return process;
}

View File

@ -1,5 +1,6 @@
## NEXT
## 4.1.6
* Fixes unawaited_futures violations.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
* Aligns Dart and Flutter SDK constraints.

View File

@ -191,7 +191,7 @@ class NetworkImageWithRetry extends ImageProvider<NetworkImageWithRetry> {
scale: key.scale,
);
} catch (error) {
request?.close();
await request?.close();
lastFailure = error is FetchFailure
? error
: FetchFailure._(

View File

@ -3,7 +3,7 @@ description: >
Image utilities for Flutter: improved network providers, effects, etc.
repository: https://github.com/flutter/packages/tree/main/packages/flutter_image
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_image%22
version: 4.1.5
version: 4.1.6
environment:
sdk: ">=2.18.0 <4.0.0"

View File

@ -1,5 +1,6 @@
## NEXT
* Fixes unawaited_futures violations.
* Updates minimum Flutter version to 3.3.
* Aligns Dart and Flutter SDK constraints.
* Replace `describeEnum` with the `name` getter.

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
@ -125,11 +127,11 @@ class _BasicMarkdownDemoState extends State<BasicMarkdownDemo> {
String? href,
String title,
) async {
showDialog<Widget>(
unawaited(showDialog<Widget>(
context: context,
builder: (BuildContext context) =>
_createDialog(context, text, href, title),
);
));
}
Widget _createDialog(

View File

@ -109,7 +109,7 @@ class DemoNotesView extends StatelessWidget {
String? href,
String title,
) async {
showDialog<Widget>(
await showDialog<Widget>(
context: context,
builder: (BuildContext context) =>
_createDialog(context, text, href, title),

View File

@ -1,5 +1,11 @@
# This custom rule set only exists to allow very targeted changes
# relative to the default repo settings, for specific use cases.
# Please do NOT add more changes here without consulting with
# #hackers-ecosystem on Discord.
include: ../../analysis_options.yaml
analyzer:
exclude:
# This directory deliberately has errors, to test `fix`.
- "test_fixes/**"

View File

@ -0,0 +1,12 @@
# This custom rule set only exists to allow very targeted changes
# relative to the default repo settings, for specific use cases.
# Please do NOT add more changes here without consulting with
# #hackers-ecosystem on Discord.
include: ../../../analysis_options.yaml
linter:
rules:
# Matches flutter/flutter, which disables this rule due to false positives
# from navigator APIs.
unawaited_futures: false

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: cascade_invocations, diagnostic_describe_all_properties
// ignore_for_file: cascade_invocations, diagnostic_describe_all_properties, unawaited_futures
import 'dart:async';

View File

@ -8,6 +8,7 @@
// ignore_for_file: avoid_print
import 'dart:async';
import 'dart:io';
import 'package:io/io.dart' as io;
import 'package:path/path.dart' as p;
@ -99,8 +100,8 @@ dependencies:
Future<Process> _streamOutput(Future<Process> processFuture) async {
final Process process = await processFuture;
stdout.addStream(process.stdout);
stderr.addStream(process.stderr);
unawaited(stdout.addStream(process.stdout));
unawaited(stderr.addStream(process.stderr));
return process;
}

View File

@ -1,5 +1,6 @@
## NEXT
## 2.0.2
* Fixes unawaited_futures violations.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
## 2.0.1

View File

@ -4,6 +4,8 @@
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
@ -185,7 +187,7 @@ class HomeScreen extends StatelessWidget {
value: '2',
child: const Text('Push w/ return value'),
onTap: () async {
FamilyCountRoute(familyData.length)
unawaited(FamilyCountRoute(familyData.length)
.push<int>(context)
.then((int? value) {
if (value != null) {
@ -195,7 +197,7 @@ class HomeScreen extends StatelessWidget {
),
);
}
});
}));
},
),
PopupMenuItem<String>(

View File

@ -2,7 +2,7 @@ name: go_router_builder
description: >-
A builder that supports generated strongly-typed route helpers for
package:go_router
version: 2.0.1
version: 2.0.2
repository: https://github.com/flutter/packages/tree/main/packages/go_router_builder
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router_builder%22

View File

@ -4,6 +4,8 @@
@TestOn('browser') // Uses package:js
import 'dart:async';
import 'package:google_identity_services_web/loader.dart';
import 'package:google_identity_services_web/src/js_interop/dom.dart' as dom;
import 'package:google_identity_services_web/src/js_loader.dart';
@ -27,7 +29,9 @@ void main() {
final dom.DomHtmlElement target = dom.document.createElement('div');
test('Injects script into desired target', () async {
loadWebSdk(target: target);
// This test doesn't simulate the callback that completes the future, and
// the code being tested runs synchronously.
unawaited(loadWebSdk(target: target));
// Target now should have a child that is a script element
final Object children = js_util.getProperty<Object>(target, 'children');

View File

@ -8,6 +8,7 @@
//
// usage: dart run tool/run_tests.dart
// (needs a `chrome` executable in $PATH, or a tweak to dart_test.yaml)
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as p;
@ -30,8 +31,8 @@ Future<void> main(List<String> args) async {
Future<Process> _streamOutput(Future<Process> processFuture) async {
final Process process = await processFuture;
stdout.addStream(process.stdout);
stderr.addStream(process.stderr);
unawaited(stdout.addStream(process.stdout));
unawaited(stderr.addStream(process.stderr));
return process;
}

View File

@ -1,3 +1,7 @@
## 2.2.8
* Fixes unawaited_futures violations.
## 2.2.7
* Removes obsolete null checks on non-nullable values.

View File

@ -154,7 +154,7 @@ class MapSampleState extends State<MapSample> {
Future<void> _goToTheLake() async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
await controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
}
}
```

View File

@ -66,7 +66,7 @@ class MapSampleState extends State<MapSample> {
Future<void> _goToTheLake() async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
await controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
}
}
// #enddocregion MapSample

View File

@ -360,47 +360,41 @@ class _GoogleMapState extends State<GoogleMap> {
return;
}
final GoogleMapController controller = await _controller.future;
// ignore: unawaited_futures
controller._updateMapConfiguration(updates);
await controller._updateMapConfiguration(updates);
_mapConfiguration = newConfig;
}
Future<void> _updateMarkers() async {
final GoogleMapController controller = await _controller.future;
// ignore: unawaited_futures
controller._updateMarkers(
await controller._updateMarkers(
MarkerUpdates.from(_markers.values.toSet(), widget.markers));
_markers = keyByMarkerId(widget.markers);
}
Future<void> _updatePolygons() async {
final GoogleMapController controller = await _controller.future;
// ignore: unawaited_futures
controller._updatePolygons(
await controller._updatePolygons(
PolygonUpdates.from(_polygons.values.toSet(), widget.polygons));
_polygons = keyByPolygonId(widget.polygons);
}
Future<void> _updatePolylines() async {
final GoogleMapController controller = await _controller.future;
// ignore: unawaited_futures
controller._updatePolylines(
await controller._updatePolylines(
PolylineUpdates.from(_polylines.values.toSet(), widget.polylines));
_polylines = keyByPolylineId(widget.polylines);
}
Future<void> _updateCircles() async {
final GoogleMapController controller = await _controller.future;
// ignore: unawaited_futures
controller._updateCircles(
await controller._updateCircles(
CircleUpdates.from(_circles.values.toSet(), widget.circles));
_circles = keyByCircleId(widget.circles);
}
Future<void> _updateTileOverlays() async {
final GoogleMapController controller = await _controller.future;
// ignore: unawaited_futures
controller._updateTileOverlays(widget.tileOverlays);
await controller._updateTileOverlays(widget.tileOverlays);
}
Future<void> onPlatformViewCreated(int id) async {
@ -410,7 +404,7 @@ class _GoogleMapState extends State<GoogleMap> {
this,
);
_controller.complete(controller);
_updateTileOverlays();
unawaited(_updateTileOverlays());
final MapCreatedCallback? onMapCreated = widget.onMapCreated;
if (onMapCreated != null) {
onMapCreated(controller);

View File

@ -2,7 +2,7 @@ name: google_maps_flutter
description: A Flutter plugin for integrating Google Maps in iOS and Android applications.
repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22
version: 2.2.7
version: 2.2.8
environment:
sdk: ">=2.18.0 <4.0.0"

View File

@ -1,3 +1,7 @@
## NEXT
* Fixes unawaited_futures violations.
## 2.4.15
* Removes obsolete null checks on non-nullable values.

View File

@ -423,41 +423,41 @@ class _ExampleGoogleMapState extends State<ExampleGoogleMap> {
return;
}
final ExampleGoogleMapController controller = await _controller.future;
controller._updateMapConfiguration(updates);
await controller._updateMapConfiguration(updates);
_mapConfiguration = newConfig;
}
Future<void> _updateMarkers() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updateMarkers(
await controller._updateMarkers(
MarkerUpdates.from(_markers.values.toSet(), widget.markers));
_markers = keyByMarkerId(widget.markers);
}
Future<void> _updatePolygons() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updatePolygons(
await controller._updatePolygons(
PolygonUpdates.from(_polygons.values.toSet(), widget.polygons));
_polygons = keyByPolygonId(widget.polygons);
}
Future<void> _updatePolylines() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updatePolylines(
await controller._updatePolylines(
PolylineUpdates.from(_polylines.values.toSet(), widget.polylines));
_polylines = keyByPolylineId(widget.polylines);
}
Future<void> _updateCircles() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updateCircles(
await controller._updateCircles(
CircleUpdates.from(_circles.values.toSet(), widget.circles));
_circles = keyByCircleId(widget.circles);
}
Future<void> _updateTileOverlays() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updateTileOverlays(widget.tileOverlays);
await controller._updateTileOverlays(widget.tileOverlays);
}
Future<void> onPlatformViewCreated(int id) async {
@ -468,7 +468,7 @@ class _ExampleGoogleMapState extends State<ExampleGoogleMap> {
this,
);
_controller.complete(controller);
_updateTileOverlays();
unawaited(_updateTileOverlays());
widget.onMapCreated?.call(controller);
}

View File

@ -1,3 +1,7 @@
## NEXT
* Fixes unawaited_futures violations.
## 2.2.3
* Removes obsolete null checks on non-nullable values.

View File

@ -423,41 +423,41 @@ class _ExampleGoogleMapState extends State<ExampleGoogleMap> {
return;
}
final ExampleGoogleMapController controller = await _controller.future;
controller._updateMapConfiguration(updates);
await controller._updateMapConfiguration(updates);
_mapConfiguration = newConfig;
}
Future<void> _updateMarkers() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updateMarkers(
await controller._updateMarkers(
MarkerUpdates.from(_markers.values.toSet(), widget.markers));
_markers = keyByMarkerId(widget.markers);
}
Future<void> _updatePolygons() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updatePolygons(
await controller._updatePolygons(
PolygonUpdates.from(_polygons.values.toSet(), widget.polygons));
_polygons = keyByPolygonId(widget.polygons);
}
Future<void> _updatePolylines() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updatePolylines(
await controller._updatePolylines(
PolylineUpdates.from(_polylines.values.toSet(), widget.polylines));
_polylines = keyByPolylineId(widget.polylines);
}
Future<void> _updateCircles() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updateCircles(
await controller._updateCircles(
CircleUpdates.from(_circles.values.toSet(), widget.circles));
_circles = keyByCircleId(widget.circles);
}
Future<void> _updateTileOverlays() async {
final ExampleGoogleMapController controller = await _controller.future;
controller._updateTileOverlays(widget.tileOverlays);
await controller._updateTileOverlays(widget.tileOverlays);
}
Future<void> onPlatformViewCreated(int id) async {
@ -468,7 +468,7 @@ class _ExampleGoogleMapState extends State<ExampleGoogleMap> {
this,
);
_controller.complete(controller);
_updateTileOverlays();
unawaited(_updateTileOverlays());
widget.onMapCreated?.call(controller);
}

View File

@ -1,3 +1,7 @@
## 6.1.2
* Fixes unawaited_futures violations.
## 6.1.1
* Removes obsolete null checks on non-nullable values.

View File

@ -70,7 +70,7 @@ class _SignInDemoState extends State<SignInDemo> {
// Now that we know that the user can access the required scopes, the app
// can call the REST API.
if (isAuthorized) {
_handleGetContact(account!);
unawaited(_handleGetContact(account!));
}
});
@ -156,7 +156,7 @@ class _SignInDemoState extends State<SignInDemo> {
_isAuthorized = isAuthorized;
});
if (isAuthorized) {
_handleGetContact(_currentUser!);
unawaited(_handleGetContact(_currentUser!));
}
}

View File

@ -296,11 +296,13 @@ class GoogleSignIn {
// Performs initialization, guarding it with the _initialization future.
Future<void> _ensureInitialized() async {
return _initialization ??= _doInitialization()
..catchError((dynamic _) {
// Invalidate initialization if it errors out.
_initialization = null;
});
_initialization ??= _doInitialization().catchError((Object e) {
// Invalidate initialization if it errors out.
_initialization = null;
// ignore: only_throw_errors
throw e;
});
return _initialization;
}
// Actually performs the initialization.
@ -317,10 +319,10 @@ class GoogleSignIn {
forceCodeForRefreshToken: forceCodeForRefreshToken,
));
GoogleSignInPlatform.instance.userDataEvents
unawaited(GoogleSignInPlatform.instance.userDataEvents
?.map((GoogleSignInUserData? userData) {
return userData != null ? GoogleSignInAccount._(this, userData) : null;
}).forEach(_setCurrentUser);
}).forEach(_setCurrentUser));
}
/// The most recently scheduled method call.

View File

@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system
for signing in with a Google account on Android and iOS.
repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
version: 6.1.1
version: 6.1.2
environment:
sdk: ">=2.18.0 <4.0.0"

View File

@ -1,3 +1,7 @@
## 0.12.0+1
* Fixes unawaited_futures violations.
## 0.12.0
* Authentication:

View File

@ -259,14 +259,14 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
Future<void> signOut() async {
await initialized;
_gisClient.signOut();
await _gisClient.signOut();
}
@override
Future<void> disconnect() async {
await initialized;
_gisClient.disconnect();
await _gisClient.disconnect();
}
@override
@ -280,7 +280,7 @@ class GoogleSignInPlugin extends GoogleSignInPlatform {
Future<void> clearAuthCache({required String token}) async {
await initialized;
_gisClient.clearAuthCache();
await _gisClient.clearAuthCache();
}
@override

View File

@ -290,7 +290,7 @@ class GisSdkClient {
/// Revokes the current authentication.
Future<void> signOut() async {
clearAuthCache();
await clearAuthCache();
id.disableAutoSelect();
}
@ -299,7 +299,7 @@ class GisSdkClient {
if (_lastTokenResponse != null) {
oauth2.revoke(_lastTokenResponse!.access_token);
}
signOut();
await signOut();
}
/// Returns true if the client has recognized this user before.

View File

@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system
for signing in with a Google account on Android, iOS and Web.
repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in_web
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
version: 0.12.0
version: 0.12.0+1
environment:
sdk: ">=2.18.0 <4.0.0"

View File

@ -1,3 +1,7 @@
## 3.1.7
* Fixes unawaited_futures violations.
## 3.1.6
* Bumps minimum in_app_purchase_android version to 0.3.0.

View File

@ -436,7 +436,7 @@ class _MyAppState extends State<_MyApp> {
purchaseDetails.status == PurchaseStatus.restored) {
final bool valid = await _verifyPurchase(purchaseDetails);
if (valid) {
deliverProduct(purchaseDetails);
unawaited(deliverProduct(purchaseDetails));
} else {
_handleInvalidPurchase(purchaseDetails);
return;

View File

@ -2,7 +2,7 @@ name: in_app_purchase
description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
version: 3.1.6
version: 3.1.7
environment:
sdk: ">=2.18.0 <4.0.0"

View File

@ -1,3 +1,7 @@
## 0.3.0+4
* Fixes unawaited_futures violations.
## 0.3.0+3
* Fixes Java lint issues.

View File

@ -397,7 +397,7 @@ class _MyAppState extends State<_MyApp> {
purchaseDetails.status == PurchaseStatus.restored) {
final bool valid = await _verifyPurchase(purchaseDetails);
if (valid) {
deliverProduct(purchaseDetails);
unawaited(deliverProduct(purchaseDetails));
} else {
_handleInvalidPurchase(purchaseDetails);
return;

View File

@ -2,7 +2,7 @@ name: in_app_purchase_android
description: An implementation for the Android platform of the Flutter `in_app_purchase` plugin. This uses the Android BillingClient APIs.
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
version: 0.3.0+3
version: 0.3.0+4
environment:
sdk: ">=2.18.0 <4.0.0"

View File

@ -54,13 +54,13 @@ void main() {
test('waits for connection before executing the operations', () async {
final Completer<void> calledCompleter1 = Completer<void>();
final Completer<void> calledCompleter2 = Completer<void>();
manager.runWithClient((BillingClient _) async {
unawaited(manager.runWithClient((BillingClient _) async {
calledCompleter1.complete();
return const BillingResultWrapper(responseCode: BillingResponse.ok);
});
manager.runWithClientNonRetryable(
}));
unawaited(manager.runWithClientNonRetryable(
(BillingClient _) async => calledCompleter2.complete(),
);
));
expect(calledCompleter1.isCompleted, equals(false));
expect(calledCompleter1.isCompleted, equals(false));
connectedCompleter.complete();
@ -74,7 +74,7 @@ void main() {
// Ensures all asynchronous connected code finishes.
await manager.runWithClientNonRetryable((_) async {});
manager.client.callHandler(
await manager.client.callHandler(
const MethodCall(onBillingServiceDisconnectedCallback,
<String, dynamic>{'handle': 0}),
);

View File

@ -1,5 +0,0 @@
include: ../../analysis_options.yaml
linter:
rules:
unawaited_futures: true

View File

@ -74,7 +74,7 @@ Future<void> main() async {
// We need to have a testWidgets test in order to initialize the image
// cache for the other tests, but they timeout if they too are testWidgets
// tests.
tester.pumpWidget(const Placeholder());
await tester.pumpWidget(const Placeholder());
});
test(

View File

@ -211,13 +211,13 @@ void main() {
NullableReturnFlutterApi.setup(mockFlutterApi);
final Completer<int?> resultCompleter = Completer<int?>();
binding.defaultBinaryMessenger.handlePlatformMessage(
unawaited(binding.defaultBinaryMessenger.handlePlatformMessage(
'dev.flutter.pigeon.NullableReturnFlutterApi.doit',
NullableReturnFlutterApi.codec.encodeMessage(<Object?>[]),
(ByteData? data) {
resultCompleter.complete(null);
},
);
));
expect(resultCompleter.future, completion(null));
@ -234,13 +234,13 @@ void main() {
final Completer<List<String?>?> resultCompleter =
Completer<List<String?>?>();
binding.defaultBinaryMessenger.handlePlatformMessage(
unawaited(binding.defaultBinaryMessenger.handlePlatformMessage(
'dev.flutter.pigeon.NullableCollectionReturnFlutterApi.doit',
NullableCollectionReturnFlutterApi.codec.encodeMessage(<Object?>[]),
(ByteData? data) {
resultCompleter.complete(null);
},
);
));
expect(resultCompleter.future, completion(null));

View File

@ -28,8 +28,10 @@ Future<int> runProcess(String command, List<String> arguments,
if (exitCode != 0 && logFailure) {
// ignore: avoid_print
print('$command $arguments failed:');
process.stdout.pipe(stdout);
process.stderr.pipe(stderr);
await Future.wait(<Future<void>>[
process.stdout.pipe(stdout),
process.stderr.pipe(stderr),
]);
}
return exitCode;
}

View File

@ -28,7 +28,7 @@ void main() {
testWidgets('reading', (WidgetTester _) async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows();
preferences.clear();
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['String'], isNull);
expect(values['bool'], isNull);
@ -39,7 +39,7 @@ void main() {
testWidgets('writing', (WidgetTester _) async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows();
preferences.clear();
await preferences.clear();
await preferences.setValue(
'String', 'flutter.String', kTestValues2['flutter.String']!);
await preferences.setValue(
@ -60,7 +60,7 @@ void main() {
testWidgets('removing', (WidgetTester _) async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows();
preferences.clear();
await preferences.clear();
const String key = 'flutter.testKey';
await preferences.setValue('String', key, kTestValues['flutter.String']!);
await preferences.setValue('Bool', key, kTestValues['flutter.bool']!);
@ -75,7 +75,7 @@ void main() {
testWidgets('clearing', (WidgetTester _) async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows();
preferences.clear();
await preferences.clear();
await preferences.setValue(
'String', 'flutter.String', kTestValues['flutter.String']!);
await preferences.setValue(

View File

@ -36,7 +36,7 @@ void main() {
test('canLaunch invalid URL passes the PlatformException through',
() async {
final UrlLauncherIOS launcher = UrlLauncherIOS(api: api);
expectLater(launcher.canLaunch('invalid://u r l'),
await expectLater(launcher.canLaunch('invalid://u r l'),
throwsA(isA<PlatformException>()));
});
@ -74,7 +74,7 @@ void main() {
test('launch invalid URL passes the PlatformException through', () async {
final UrlLauncherIOS launcher = UrlLauncherIOS(api: api);
expectLater(
await expectLater(
launcher.launch(
'invalid://u r l',
useSafariVC: false,

View File

@ -34,13 +34,13 @@ void main() {
test('invalid URL returns a PlatformException', () async {
final UrlLauncherMacOS launcher = UrlLauncherMacOS(api: api);
expectLater(launcher.canLaunch('invalid://u r l'),
await expectLater(launcher.canLaunch('invalid://u r l'),
throwsA(isA<PlatformException>()));
});
test('passes unexpected PlatformExceptions through', () async {
final UrlLauncherMacOS launcher = UrlLauncherMacOS(api: api);
expectLater(launcher.canLaunch('unexpectedthrow://someexception'),
await expectLater(launcher.canLaunch('unexpectedthrow://someexception'),
throwsA(isA<PlatformException>()));
});
});
@ -78,7 +78,7 @@ void main() {
test('invalid URL returns a PlatformException', () async {
final UrlLauncherMacOS launcher = UrlLauncherMacOS(api: api);
expectLater(
await expectLater(
launcher.launch(
'invalid://u r l',
useSafariVC: false,
@ -93,7 +93,7 @@ void main() {
test('passes unexpected PlatformExceptions through', () async {
final UrlLauncherMacOS launcher = UrlLauncherMacOS(api: api);
expectLater(
await expectLater(
launcher.launch(
'unexpectedthrow://someexception',
useSafariVC: false,

View File

@ -1,3 +1,7 @@
## 0.1.0+5
* Fixes unawaited_futures violations.
## 0.1.0+4
* Removes obsolete null checks on non-nullable values.

View File

@ -151,7 +151,7 @@ class BenchmarkServer {
'Requested to run benchmark ${benchmarkIterator.current}, but '
'got results for $benchmarkName.',
));
server.close();
unawaited(server.close());
}
// Trace data is null when the benchmark is not frame-based, such as RawRecorder.
@ -180,7 +180,7 @@ class BenchmarkServer {
} else if (request.requestedUri.path.endsWith('/on-error')) {
final Map<String, dynamic> errorDetails =
json.decode(await request.readAsString()) as Map<String, dynamic>;
server.close();
unawaited(server.close());
// Keep the stack trace as a string. It's thrown in the browser, not this Dart VM.
final String errorMessage =
'Caught browser-side error: ${errorDetails['error']}\n${errorDetails['stackTrace']}';
@ -314,7 +314,7 @@ class BenchmarkServer {
);
await chrome?.whenExits;
}
server.close();
unawaited(server.close());
}
}
}

View File

@ -2,7 +2,7 @@ name: web_benchmarks
description: A benchmark harness for performance-testing Flutter apps in Chrome.
repository: https://github.com/flutter/packages/tree/main/packages/web_benchmarks
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+web_benchmarks%22
version: 0.1.0+4
version: 0.1.0+5
environment:
sdk: ">=2.18.0 <4.0.0"

View File

@ -0,0 +1,8 @@
# TODO(stuartmorgan): Remove this file and fix all the unawaited_futures
# violations. See https://github.com/flutter/flutter/issues/127323
include: ../../../analysis_options.yaml
linter:
rules:
unawaited_futures: false

View File

@ -0,0 +1,8 @@
# TODO(stuartmorgan): Remove this file and fix all the unawaited_futures
# violations. See https://github.com/flutter/flutter/issues/127323
include: ../../../analysis_options.yaml
linter:
rules:
unawaited_futures: false

View File

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:html' as html;
import 'dart:io';
@ -20,23 +21,23 @@ Future<void> main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final HttpServer server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
server.forEach((HttpRequest request) {
unawaited(server.forEach((HttpRequest request) {
if (request.uri.path == '/hello.txt') {
request.response.writeln('Hello, world.');
} else {
fail('unexpected request: ${request.method} ${request.uri}');
}
request.response.close();
});
}));
final String prefixUrl = 'http://${server.address.address}:${server.port}';
final String primaryUrl = '$prefixUrl/hello.txt';
testWidgets('loadRequest', (WidgetTester tester) async {
final WebWebViewController controller =
WebWebViewController(const PlatformWebViewControllerCreationParams())
..loadRequest(
LoadRequestParams(uri: Uri.parse(primaryUrl)),
);
WebWebViewController(const PlatformWebViewControllerCreationParams());
await controller.loadRequest(
LoadRequestParams(uri: Uri.parse(primaryUrl)),
);
await tester.pumpWidget(
Directionality(
@ -58,10 +59,10 @@ Future<void> main() async {
testWidgets('loadHtmlString', (WidgetTester tester) async {
final WebWebViewController controller =
WebWebViewController(const PlatformWebViewControllerCreationParams())
..loadHtmlString(
'data:text/html;charset=utf-8,${Uri.encodeFull('test html')}',
);
WebWebViewController(const PlatformWebViewControllerCreationParams());
await controller.loadHtmlString(
'data:text/html;charset=utf-8,${Uri.encodeFull('test html')}',
);
await tester.pumpWidget(
Directionality(

View File

@ -0,0 +1,8 @@
# TODO(stuartmorgan): Remove this file and fix all the unawaited_futures
# violations. See https://github.com/flutter/flutter/issues/127323
include: ../../../analysis_options.yaml
linter:
rules:
unawaited_futures: false

View File

@ -11,17 +11,24 @@
# which references this file from source, but out-of-repo.
# Contact stuartmorgan or devoncarew for assistance if necessary.
# Temporary opt-outs of unawaited_futures; see
# https://github.com/flutter/flutter/issues/127323
- camera/camera_android_camerax
- webview_flutter/webview_flutter
- webview_flutter/webview_flutter_android
- webview_flutter/webview_flutter_wkwebview
# Opts out of unawaited_futures, matching flutter/flutter's disabling due
# to interactions with animation.
- animations
# Deliberately uses flutter_lints, as that's what it is demonstrating.
- flutter_lints/example
# Adopts some flutter_tools rules regarding public api docs due to being an
# extension of the tool and using tools base code.
- flutter_migrate
# Adds unawaited_futures. We should investigating adding this to the root
# options instead.
- metrics_center
# Has some test files that are intentionally broken to conduct dart fix tests.
# Also opts out of unawaited_futures, matching flutter/flutter.
- go_router
# Has some constructions that are currently handled poorly by dart format.
- rfw/example
# Disables docs requirements, as it is test code.
- web_benchmarks/testing/test_app
# Has some test files that are intentionally broken to conduct dart fix tests.
- go_router

View File

@ -324,7 +324,7 @@ abstract class PackageLoopingCommand extends PackageCommand {
}
_currentPackageEntry = null;
completeRun();
await completeRun();
print('\n');
// If there were any errors reported, summarize them and exit.

View File

@ -177,7 +177,8 @@ Future<bool> _isDevChange(List<String> pathComponents,
// Entry point for the 'custom-test' command, which is only for CI and
// local testing.
pathComponents.first == 'run_tests.sh' ||
// Ignoring lints doesn't affect clients.
// Lints don't affect clients.
pathComponents.contains('analysis_options.yaml') ||
pathComponents.contains('lint-baseline.xml') ||
// Example build files are very unlikely to be interesting to clients.
_isExampleBuildFile(pathComponents) ||

View File

@ -249,7 +249,8 @@ $dependencyOverridesKey:
// example app doesn't. Since integration tests are run in the example app,
// it needs the overrides in order for tests to pass.
for (final RepositoryPackage example in package.getExamples()) {
_addDependencyOverridesIfNecessary(example, localDependencies, versions,
await _addDependencyOverridesIfNecessary(
example, localDependencies, versions,
additionalPackagesToOverride: packagesToOverride);
}

View File

@ -159,7 +159,7 @@ void main() {
test('fails if AUTHORS is missing', () async {
final RepositoryPackage package =
createFakePackage('a_package', packagesDir);
package.authorsFile.delete();
package.authorsFile.deleteSync();
Error? commandError;
final List<String> output = await runCapturingPrint(
@ -183,7 +183,7 @@ void main() {
packagesDir.parent
.childDirectory('third_party')
.childDirectory('packages'));
package.authorsFile.delete();
package.authorsFile.deleteSync();
final List<String> output =
await runCapturingPrint(runner, <String>['publish-check']);

View File

@ -100,7 +100,7 @@ void main() {
const String subpackageName = 'special_test';
final RepositoryPackage miscSubpackage =
createFakePackage(subpackageName, package.directory);
miscSubpackage.readmeFile.delete();
miscSubpackage.readmeFile.deleteSync();
final List<String> output =
await runCapturingPrint(runner, <String>['readme-check']);

View File

@ -879,6 +879,7 @@ packages/plugin/example/android/lint-baseline.xml
packages/plugin/example/android/src/androidTest/foo/bar/FooTest.java
packages/plugin/example/ios/RunnerTests/Foo.m
packages/plugin/example/ios/RunnerUITests/info.plist
packages/plugin/analysis_options.yaml
packages/plugin/CHANGELOG.md
''')),
];