Unverified Commit cda2c223 authored by xster's avatar xster Committed by GitHub

Turn on unawaited_futures in flutter_tools (#21048)

parent f2442b8a
...@@ -5,4 +5,4 @@ include: ../analysis_options.yaml ...@@ -5,4 +5,4 @@ include: ../analysis_options.yaml
linter: linter:
rules: rules:
- public_member_api_docs - public_member_api_docs
...@@ -2,3 +2,7 @@ ...@@ -2,3 +2,7 @@
# the ones from above, which include the `public_member_api_docs` rule). # the ones from above, which include the `public_member_api_docs` rule).
include: ../../analysis_options.yaml include: ../../analysis_options.yaml
linter:
rules:
- unawaited_futures
...@@ -236,7 +236,11 @@ class AndroidWorkflow extends DoctorValidator implements Workflow { ...@@ -236,7 +236,11 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
environment: androidSdk.sdkManagerEnv, environment: androidSdk.sdkManagerEnv,
); );
process.stdin.addStream(stdin); // The real stdin will never finish streaming. Pipe until the child process
// finishes.
process.stdin.addStream(stdin); // ignore: unawaited_futures
// Wait for stdout and stderr to be fully processed, because process.exitCode
// may complete first.
await waitGroup<void>(<Future<void>>[ await waitGroup<void>(<Future<void>>[
stdout.addStream(process.stdout), stdout.addStream(process.stdout),
stderr.addStream(process.stderr), stderr.addStream(process.stderr),
......
...@@ -191,7 +191,9 @@ Future<int> runInteractively(List<String> command, { ...@@ -191,7 +191,9 @@ Future<int> runInteractively(List<String> command, {
allowReentrantFlutter: allowReentrantFlutter, allowReentrantFlutter: allowReentrantFlutter,
environment: environment, environment: environment,
); );
process.stdin.addStream(stdin); // The real stdin will never finish streaming. Pipe until the child process
// finishes.
process.stdin.addStream(stdin); // ignore: unawaited_futures
// Wait for stdout and stderr to be fully processed, because process.exitCode // Wait for stdout and stderr to be fully processed, because process.exitCode
// may complete first. // may complete first.
await Future.wait<dynamic>(<Future<dynamic>>[ await Future.wait<dynamic>(<Future<dynamic>>[
......
...@@ -92,7 +92,8 @@ class AnalyzeOnce extends AnalyzeBase { ...@@ -92,7 +92,8 @@ class AnalyzeOnce extends AnalyzeBase {
}); });
await server.start(); await server.start();
server.onExit.then((int exitCode) { // Completing the future in the callback can't fail.
server.onExit.then((int exitCode) { // ignore: unawaited_futures
if (!analysisCompleter.isCompleted) { if (!analysisCompleter.isCompleted) {
analysisCompleter.completeError('analysis server exited: $exitCode'); analysisCompleter.completeError('analysis server exited: $exitCode');
} }
......
...@@ -82,7 +82,7 @@ class AttachCommand extends FlutterCommand { ...@@ -82,7 +82,7 @@ class AttachCommand extends FlutterCommand {
@override @override
Future<Null> validateCommand() async { Future<Null> validateCommand() async {
super.validateCommand(); await super.validateCommand();
if (await findTargetDevice() == null) if (await findTargetDevice() == null)
throwToolExit(null); throwToolExit(null);
observatoryPort; observatoryPort;
......
...@@ -444,7 +444,8 @@ class _PortForwarder { ...@@ -444,7 +444,8 @@ class _PortForwarder {
.transform(utf8.decoder) .transform(utf8.decoder)
.transform(const LineSplitter()) .transform(const LineSplitter())
.listen((String data) { printTrace(data); }); .listen((String data) { printTrace(data); });
process.exitCode.then((int c) { // Best effort to print the exit code.
process.exitCode.then((int c) { // ignore: unawaited_futures
printTrace("'${command.join(' ')}' exited with exit code $c"); printTrace("'${command.join(' ')}' exited with exit code $c");
}); });
printTrace('Set up forwarding from $localPort to $address:$remotePort'); printTrace('Set up forwarding from $localPort to $address:$remotePort');
......
...@@ -45,8 +45,7 @@ class AnalysisServer { ...@@ -45,8 +45,7 @@ class AnalysisServer {
printTrace('dart ${command.skip(1).join(' ')}'); printTrace('dart ${command.skip(1).join(' ')}');
_process = await processManager.start(command); _process = await processManager.start(command);
// This callback hookup can't throw. // This callback hookup can't throw.
_process.exitCode _process.exitCode.whenComplete(() => _process = null); // ignore: unawaited_futures
.whenComplete(() => _process = null); // ignore: unawaited_futures
final Stream<String> errorStream = final Stream<String> errorStream =
_process.stderr.transform(utf8.decoder).transform(const LineSplitter()); _process.stderr.transform(utf8.decoder).transform(const LineSplitter());
......
...@@ -153,9 +153,7 @@ Future<Map<String, String>> getCodeSigningIdentityDevelopmentTeam({ ...@@ -153,9 +153,7 @@ Future<Map<String, String>> getCodeSigningIdentityDevelopmentTeam({
); );
final Process opensslProcess = await runCommand(const <String>['openssl', 'x509', '-subject']); final Process opensslProcess = await runCommand(const <String>['openssl', 'x509', '-subject']);
opensslProcess.stdin await (opensslProcess.stdin..write(signingCertificate)).close();
..write(signingCertificate)
..close();
final String opensslOutput = await utf8.decodeStream(opensslProcess.stdout); final String opensslOutput = await utf8.decodeStream(opensslProcess.stdout);
// Fire and forget discard of the stderr stream so we don't hold onto resources. // Fire and forget discard of the stderr stream so we don't hold onto resources.
......
...@@ -762,7 +762,7 @@ abstract class ResidentRunner { ...@@ -762,7 +762,7 @@ abstract class ResidentRunner {
await handleTerminalCommand(command); await handleTerminalCommand(command);
} catch (error, st) { } catch (error, st) {
printError('$error\n$st'); printError('$error\n$st');
_cleanUpAndExit(null); await _cleanUpAndExit(null);
} finally { } finally {
_processingUserRequest = false; _processingUserRequest = false;
} }
......
...@@ -590,21 +590,28 @@ class HotRunner extends ResidentRunner { ...@@ -590,21 +590,28 @@ class HotRunner extends ResidentRunner {
pause: pause pause: pause
); );
countExpectedReports += reports.length; countExpectedReports += reports.length;
Future.wait(reports).catchError((dynamic error) { await Future
return <Map<String, dynamic>>[error]; .wait(reports)
}).then((List<Map<String, dynamic>> list) { .catchError((dynamic error) {
// TODO(aam): Investigate why we are validating only first reload report, return <Map<String, dynamic>>[error];
// which seems to be current behavior })
final Map<String, dynamic> firstReport = list.first; .then(
// Don't print errors because they will be printed further down when (List<Map<String, dynamic>> list) {
// `validateReloadReport` is called again. // TODO(aam): Investigate why we are validating only first reload report,
device.updateReloadStatus(validateReloadReport(firstReport, // which seems to be current behavior
printErrors: false)); final Map<String, dynamic> firstReport = list.first;
if (!retrieveFirstReloadReport.isCompleted) // Don't print errors because they will be printed further down when
retrieveFirstReloadReport.complete(firstReport); // `validateReloadReport` is called again.
}, onError: (dynamic error, StackTrace stack) { device.updateReloadStatus(
retrieveFirstReloadReport.completeError(error, stack); validateReloadReport(firstReport, printErrors: false)
}); );
if (!retrieveFirstReloadReport.isCompleted)
retrieveFirstReloadReport.complete(firstReport);
},
onError: (dynamic error, StackTrace stack) {
retrieveFirstReloadReport.completeError(error, stack);
},
);
} }
if (countExpectedReports == 0) { if (countExpectedReports == 0) {
......
...@@ -157,7 +157,8 @@ class FlutterTesterDevice extends Device { ...@@ -157,7 +157,8 @@ class FlutterTesterDevice extends Device {
'FLUTTER_TEST': 'true', 'FLUTTER_TEST': 'true',
}, },
); );
_process.exitCode.then((_) => _isRunning = false); // Setting a bool can't fail in the callback.
_process.exitCode.then((_) => _isRunning = false); // ignore: unawaited_futures
_process.stdout _process.stdout
.transform(utf8.decoder) .transform(utf8.decoder)
.transform(const LineSplitter()) .transform(const LineSplitter())
......
...@@ -43,8 +43,8 @@ void main() { ...@@ -43,8 +43,8 @@ void main() {
expect(response['id'], 0); expect(response['id'], 0);
expect(response['result'], isNotEmpty); expect(response['result'], isNotEmpty);
expect(response['result'] is String, true); expect(response['result'] is String, true);
responses.close(); await responses.close();
commands.close(); await commands.close();
}); });
testUsingContext('printError should send daemon.logMessage event', () async { testUsingContext('printError should send daemon.logMessage event', () async {
...@@ -64,8 +64,8 @@ void main() { ...@@ -64,8 +64,8 @@ void main() {
final Map<String, String> logMessage = response['params'].cast<String, String>(); final Map<String, String> logMessage = response['params'].cast<String, String>();
expect(logMessage['level'], 'error'); expect(logMessage['level'], 'error');
expect(logMessage['message'], 'daemon.logMessage test'); expect(logMessage['message'], 'daemon.logMessage test');
responses.close(); await responses.close();
commands.close(); await commands.close();
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => notifyingLogger, Logger: () => notifyingLogger,
}); });
...@@ -103,9 +103,8 @@ void main() { ...@@ -103,9 +103,8 @@ void main() {
notifyingLogger: notifyingLogger notifyingLogger: notifyingLogger
); );
commands.add(<String, dynamic>{'id': 0, 'method': 'daemon.shutdown'}); commands.add(<String, dynamic>{'id': 0, 'method': 'daemon.shutdown'});
return daemon.onExit.then<Null>((int code) { return daemon.onExit.then<Null>((int code) async {
responses.close(); await commands.close();
commands.close();
expect(code, 0); expect(code, 0);
}); });
}); });
...@@ -127,8 +126,8 @@ void main() { ...@@ -127,8 +126,8 @@ void main() {
final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
expect(response['id'], 0); expect(response['id'], 0);
expect(response['error'], contains('appId is required')); expect(response['error'], contains('appId is required'));
responses.close(); await responses.close();
commands.close(); await commands.close();
}); });
testUsingContext('ext.flutter.debugPaint via service extension without an appId should report an error', () async { testUsingContext('ext.flutter.debugPaint via service extension without an appId should report an error', () async {
...@@ -154,8 +153,8 @@ void main() { ...@@ -154,8 +153,8 @@ void main() {
final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
expect(response['id'], 0); expect(response['id'], 0);
expect(response['error'], contains('appId is required')); expect(response['error'], contains('appId is required'));
responses.close(); await responses.close();
commands.close(); await commands.close();
}); });
testUsingContext('app.stop without appId should report an error', () async { testUsingContext('app.stop without appId should report an error', () async {
...@@ -175,8 +174,8 @@ void main() { ...@@ -175,8 +174,8 @@ void main() {
final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
expect(response['id'], 0); expect(response['id'], 0);
expect(response['error'], contains('appId is required')); expect(response['error'], contains('appId is required'));
responses.close(); await responses.close();
commands.close(); await commands.close();
}); });
testUsingContext('daemon should send showMessage on startup if no Android devices are available', () async { testUsingContext('daemon should send showMessage on startup if no Android devices are available', () async {
...@@ -212,11 +211,11 @@ void main() { ...@@ -212,11 +211,11 @@ void main() {
final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
expect(response['id'], 0); expect(response['id'], 0);
expect(response['result'], isList); expect(response['result'], isList);
responses.close(); await responses.close();
commands.close(); await commands.close();
}); });
testUsingContext('should send device.added event when device is discovered', () { testUsingContext('should send device.added event when device is discovered', () async {
final StreamController<Map<String, dynamic>> commands = new StreamController<Map<String, dynamic>>(); final StreamController<Map<String, dynamic>> commands = new StreamController<Map<String, dynamic>>();
final StreamController<Map<String, dynamic>> responses = new StreamController<Map<String, dynamic>>(); final StreamController<Map<String, dynamic>> responses = new StreamController<Map<String, dynamic>>();
daemon = new Daemon( daemon = new Daemon(
...@@ -229,15 +228,15 @@ void main() { ...@@ -229,15 +228,15 @@ void main() {
daemon.deviceDomain.addDeviceDiscoverer(discoverer); daemon.deviceDomain.addDeviceDiscoverer(discoverer);
discoverer.addDevice(new MockAndroidDevice()); discoverer.addDevice(new MockAndroidDevice());
return responses.stream.skipWhile(_isConnectedEvent).first.then((Map<String, dynamic> response) { return await responses.stream.skipWhile(_isConnectedEvent).first.then((Map<String, dynamic> response) async {
expect(response['event'], 'device.added'); expect(response['event'], 'device.added');
expect(response['params'], isMap); expect(response['params'], isMap);
final Map<String, dynamic> params = response['params']; final Map<String, dynamic> params = response['params'];
expect(params['platform'], isNotEmpty); // the mock device has a platform of 'android-arm' expect(params['platform'], isNotEmpty); // the mock device has a platform of 'android-arm'
responses.close(); await responses.close();
commands.close(); await commands.close();
}); });
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidWorkflow: () => new MockAndroidWorkflow(), AndroidWorkflow: () => new MockAndroidWorkflow(),
...@@ -261,8 +260,8 @@ void main() { ...@@ -261,8 +260,8 @@ void main() {
final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
expect(response['id'], 0); expect(response['id'], 0);
expect(response['error'], contains('emulatorId is required')); expect(response['error'], contains('emulatorId is required'));
responses.close(); await responses.close();
commands.close(); await commands.close();
}); });
testUsingContext('emulator.getEmulators should respond with list', () async { testUsingContext('emulator.getEmulators should respond with list', () async {
...@@ -277,8 +276,8 @@ void main() { ...@@ -277,8 +276,8 @@ void main() {
final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent);
expect(response['id'], 0); expect(response['id'], 0);
expect(response['result'], isList); expect(response['result'], isList);
responses.close(); await responses.close();
commands.close(); await commands.close();
}); });
}); });
......
...@@ -276,7 +276,7 @@ void main() { ...@@ -276,7 +276,7 @@ void main() {
'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0\n' 'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0\n'
))); )));
generator.recompile( await generator.recompile(
'/path/to/main.dart', null /* invalidatedFiles */ '/path/to/main.dart', null /* invalidatedFiles */
).then((CompilerOutput output) { ).then((CompilerOutput output) {
expect(mockFrontendServerStdIn.getAndClear(), expect(mockFrontendServerStdIn.getAndClear(),
...@@ -320,7 +320,8 @@ void main() { ...@@ -320,7 +320,8 @@ void main() {
compileExpressionResponseCompleter2.future, compileExpressionResponseCompleter2.future,
])); ]));
generator.recompile( // The test manages timing via completers.
generator.recompile( // ignore: unawaited_futures
'/path/to/main.dart', null /* invalidatedFiles */ '/path/to/main.dart', null /* invalidatedFiles */
).then((CompilerOutput outputCompile) { ).then((CompilerOutput outputCompile) {
expect(logger.errorText, expect(logger.errorText,
...@@ -332,8 +333,9 @@ void main() { ...@@ -332,8 +333,9 @@ void main() {
))); )));
}); });
// The test manages timing via completers.
final Completer<bool> lastExpressionCompleted = new Completer<bool>(); final Completer<bool> lastExpressionCompleted = new Completer<bool>();
generator.compileExpression('0+1', null, null, null, null, false).then( generator.compileExpression('0+1', null, null, null, null, false).then( // ignore: unawaited_futures
(CompilerOutput outputExpression) { (CompilerOutput outputExpression) {
expect(outputExpression, isNotNull); expect(outputExpression, isNotNull);
expect(outputExpression.outputFilename, expect(outputExpression.outputFilename,
...@@ -344,7 +346,8 @@ void main() { ...@@ -344,7 +346,8 @@ void main() {
))); )));
}); });
generator.compileExpression('1+1', null, null, null, null, false).then( // The test manages timing via completers.
generator.compileExpression('1+1', null, null, null, null, false).then( // ignore: unawaited_futures
(CompilerOutput outputExpression) { (CompilerOutput outputExpression) {
expect(outputExpression, isNotNull); expect(outputExpression, isNotNull);
expect(outputExpression.outputFilename, expect(outputExpression.outputFilename,
......
...@@ -28,12 +28,12 @@ void main() { ...@@ -28,12 +28,12 @@ void main() {
Future<Null> expectDevice(String id, List<Device> expected) async { Future<Null> expectDevice(String id, List<Device> expected) async {
expect(await deviceManager.getDevicesById(id).toList(), expected); expect(await deviceManager.getDevicesById(id).toList(), expected);
} }
expectDevice('01abfc49119c410e', <Device>[device2]); await expectDevice('01abfc49119c410e', <Device>[device2]);
expectDevice('Nexus 5X', <Device>[device2]); await expectDevice('Nexus 5X', <Device>[device2]);
expectDevice('0553790d0a4e726f', <Device>[device1]); await expectDevice('0553790d0a4e726f', <Device>[device1]);
expectDevice('Nexus 5', <Device>[device1]); await expectDevice('Nexus 5', <Device>[device1]);
expectDevice('0553790', <Device>[device1]); await expectDevice('0553790', <Device>[device1]);
expectDevice('Nexus', <Device>[device1, device2]); await expectDevice('Nexus', <Device>[device1, device2]);
}); });
}); });
} }
......
...@@ -62,12 +62,12 @@ void main() { ...@@ -62,12 +62,12 @@ void main() {
expect(await testEmulatorManager.getEmulatorsMatching(id), expected); expect(await testEmulatorManager.getEmulatorsMatching(id), expected);
} }
expectEmulator('Nexus_5', <Emulator>[emulator1]); await expectEmulator('Nexus_5', <Emulator>[emulator1]);
expectEmulator('Nexus_5X', <Emulator>[emulator2]); await expectEmulator('Nexus_5X', <Emulator>[emulator2]);
expectEmulator('Nexus_5X_API_27_x86', <Emulator>[emulator2]); await expectEmulator('Nexus_5X_API_27_x86', <Emulator>[emulator2]);
expectEmulator('Nexus', <Emulator>[emulator1, emulator2]); await expectEmulator('Nexus', <Emulator>[emulator1, emulator2]);
expectEmulator('iOS Simulator', <Emulator>[emulator3]); await expectEmulator('iOS Simulator', <Emulator>[emulator3]);
expectEmulator('ios', <Emulator>[emulator3]); await expectEmulator('ios', <Emulator>[emulator3]);
}); });
testUsingContext('create emulator with an empty name does not fail', testUsingContext('create emulator with an empty name does not fail',
......
...@@ -89,7 +89,9 @@ class FlutterTestDriver { ...@@ -89,7 +89,9 @@ class FlutterTestDriver {
workingDirectory: _projectFolder.path, workingDirectory: _projectFolder.path,
environment: <String, String>{'FLUTTER_TEST': 'true'}); environment: <String, String>{'FLUTTER_TEST': 'true'});
_proc.exitCode.then((int code) { // This class doesn't use the result of the future. It's made available
// via a getter for external uses.
_proc.exitCode.then((int code) { // ignore: unawaited_futures
_debugPrint('Process exited ($code)'); _debugPrint('Process exited ($code)');
_hasExited = true; _hasExited = true;
}); });
......
...@@ -97,7 +97,7 @@ void main() { ...@@ -97,7 +97,7 @@ void main() {
testInMemory('exits on already materialized module', () async { testInMemory('exits on already materialized module', () async {
final FlutterProject project = await aModuleProject(); final FlutterProject project = await aModuleProject();
await project.android.materialize(); await project.android.materialize();
expectToolExitLater(project.android.materialize(), contains('already materialized')); return expectToolExitLater(project.android.materialize(), contains('already materialized'));
}); });
testInMemory('creates android/app folder in place of .android/app', () async { testInMemory('creates android/app folder in place of .android/app', () async {
final FlutterProject project = await aModuleProject(); final FlutterProject project = await aModuleProject();
......
// Copyright 2016 The Chromium Authors. All rights reserved. // Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -134,7 +135,7 @@ void main() { ...@@ -134,7 +135,7 @@ void main() {
expect(uri.port, 99); expect(uri.port, 99);
expect('$uri', 'http://127.0.0.1:99/PTwjm8Ii8qg=/'); expect('$uri', 'http://127.0.0.1:99/PTwjm8Ii8qg=/');
discoverer.cancel(); await discoverer.cancel();
logReader.dispose(); logReader.dispose();
}); });
...@@ -153,7 +154,7 @@ void main() { ...@@ -153,7 +154,7 @@ void main() {
expect(uri.port, 1243); expect(uri.port, 1243);
expect('$uri', 'http://127.0.0.1:1243/PTwjm8Ii8qg=/'); expect('$uri', 'http://127.0.0.1:1243/PTwjm8Ii8qg=/');
discoverer.cancel(); await discoverer.cancel();
logReader.dispose(); logReader.dispose();
}); });
...@@ -172,7 +173,7 @@ void main() { ...@@ -172,7 +173,7 @@ void main() {
expect(uri.port, 99); expect(uri.port, 99);
expect('$uri', 'http://127.0.0.1:99/PTwjm8Ii8qg=/'); expect('$uri', 'http://127.0.0.1:99/PTwjm8Ii8qg=/');
discoverer.cancel(); await discoverer.cancel();
logReader.dispose(); logReader.dispose();
}); });
...@@ -192,7 +193,7 @@ void main() { ...@@ -192,7 +193,7 @@ void main() {
expect(uri.port, 54777); expect(uri.port, 54777);
expect('$uri', 'http://[::1]:54777/PTwjm8Ii8qg=/'); expect('$uri', 'http://[::1]:54777/PTwjm8Ii8qg=/');
discoverer.cancel(); await discoverer.cancel();
logReader.dispose(); logReader.dispose();
}); });
}); });
......
...@@ -81,7 +81,8 @@ Future<Null> main() async { ...@@ -81,7 +81,8 @@ Future<Null> main() async {
stdout.write('> '); stdout.write('> ');
}); });
daemon.exitCode.then<Null>((int code) { // Print in the callback can't fail.
daemon.exitCode.then<Null>((int code) { // ignore: unawaited_futures
print('daemon exiting ($code)'); print('daemon exiting ($code)');
exit(code); exit(code);
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment