Unverified Commit c6b636fa authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] Replace Future.catchError() with Future.then(onError: ...) (#120637)

* wip run_local_linter.dart

* get run_local_linter.dart working

* slow working implementation

* speed up run_local_linter.dart

* fix run_local_linter.dart

* remove catchError

* another fix

* fix another

* fix

* more fixes

* fix moar

* fix moar

* fix

* finish

* fix tests

* clean up further

* code review

* delete run_local_linter.dart
parent 8d150833
......@@ -123,10 +123,12 @@ class _DaemonServer {
// We have to listen to socket.done. Otherwise when the connection is
// reset, we will receive an uncatchable exception.
// https://github.com/dart-lang/sdk/issues/25518
final Future<void> socketDone = socket.done.catchError((Object error, StackTrace stackTrace) {
logger.printError('Socket error: $error');
logger.printTrace('$stackTrace');
});
final Future<void> socketDone = socket.done.then<void>(
(_) {},
onError: (Object error, StackTrace stackTrace) {
logger.printError('Socket error: $error');
logger.printTrace('$stackTrace');
});
final Daemon daemon = Daemon(
DaemonConnection(
daemonStreams: DaemonStreams.fromSocket(socket, logger: logger),
......@@ -278,7 +280,7 @@ abstract class Domain {
}).then<Object?>((Object? result) {
daemon.connection.sendResponse(id, _toJsonable(result));
return null;
}).catchError((Object error, StackTrace stackTrace) {
}, onError: (Object error, StackTrace stackTrace) {
daemon.connection.sendErrorResponse(id, _toJsonable(error), stackTrace);
return null;
});
......@@ -1418,7 +1420,9 @@ class ProxyDomain extends Domain {
globals.logger.printTrace('Socket error: $error, $stackTrace');
});
unawaited(socket.done.catchError((Object error, StackTrace stackTrace) {
unawaited(socket.done.then<Object?>(
(Object? obj) => obj,
onError: (Object error, StackTrace stackTrace) {
// Socket error, probably disconnected.
globals.logger.printTrace('Socket error: $error, $stackTrace');
}).then((Object? _) {
......
......@@ -42,10 +42,17 @@ class ValidateProject {
continue;
}
if (!results.containsKey(validator) && validator.supportsProject(project)) {
results[validator] = validator.start(project).catchError((Object exception, StackTrace trace) {
hasCrash = true;
return <ProjectValidatorResult>[ProjectValidatorResult.crash(exception, trace)];
});
results[validator] = validator
.start(project)
.then(
(List<ProjectValidatorResult> results) => results,
onError: (Object exception, StackTrace trace) {
hasCrash = true;
return <ProjectValidatorResult>[
ProjectValidatorResult.crash(exception, trace),
];
},
);
}
}
......
......@@ -507,8 +507,10 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter {
final Completer<Object?> completer = Completer<Object?>();
_reverseRequestCompleters[id] = completer;
completer.future
.then((Object? value) => sendResponseToFlutter(id, value))
.catchError((Object? e) => sendResponseToFlutter(id, e.toString(), error: true));
.then(
(Object? value) => sendResponseToFlutter(id, value),
onError: (Object? e) => sendResponseToFlutter(id, e.toString(), error: true),
);
if (_requestsToForwardToClient.contains(method)) {
// Forward the request to the client in an event.
......
......@@ -513,40 +513,54 @@ class ProxiedPortForwarder extends DevicePortForwarder {
final Stream<List<int>> dataStream = connection.listenToEvent('proxy.data.$id').asyncExpand((DaemonEventData event) => event.binary);
dataStream.listen(socket.add);
final Future<DaemonEventData> disconnectFuture = connection.listenToEvent('proxy.disconnected.$id').first;
unawaited(disconnectFuture.then((_) {
socket.close();
}).catchError((_) {
// The event is not guaranteed to be sent if we initiated the disconnection.
// Do nothing here.
}));
unawaited(disconnectFuture.then<void>((_) async {
try {
await socket.close();
} on Exception {
// ignore
}
},
onError: (_) {
// The event is not guaranteed to be sent if we initiated the disconnection.
// Do nothing here.
},
));
socket.listen((Uint8List data) {
unawaited(connection.sendRequest('proxy.write', <String, Object>{
'id': id,
}, data).catchError((Object error, StackTrace stackTrace) {
// Log the error, but proceed normally. Network failure should not
// crash the tool. If this is critical, the place where the connection
// is being used would crash.
_logger.printWarning('Write to remote proxy error: $error');
_logger.printTrace('Write to remote proxy error: $error, stack trace: $stackTrace');
return null;
}));
}, data).then(
(Object? obj) => obj,
onError: (Object error, StackTrace stackTrace) {
// Log the error, but proceed normally. Network failure should not
// crash the tool. If this is critical, the place where the connection
// is being used would crash.
_logger.printWarning('Write to remote proxy error: $error');
_logger.printTrace('Write to remote proxy error: $error, stack trace: $stackTrace');
return null;
},
));
});
_connectedSockets.add(socket);
unawaited(socket.done.catchError((Object error, StackTrace stackTrace) {
unawaited(socket.done.then(
(Object? obj) => obj,
onError: (Object error, StackTrace stackTrace) {
// Do nothing here. Everything will be handled in the `then` block below.
return false;
}).whenComplete(() {
// Send a proxy disconnect event just in case.
unawaited(connection.sendRequest('proxy.disconnect', <String, Object>{
'id': id,
}).catchError((Object error, StackTrace stackTrace) {
// Ignore the error here. There might be a race condition when the
// remote end also disconnects. In any case, this request is just to
// notify the remote end to disconnect and we should not crash when
// there is an error here.
return null;
}));
}).then(
(Object? obj) => obj,
onError: (Object error, StackTrace stackTrace) {
// Ignore the error here. There might be a race condition when the
// remote end also disconnects. In any case, this request is just to
// notify the remote end to disconnect and we should not crash when
// there is an error here.
return null;
},
));
_connectedSockets.remove(socket);
}));
}, onError: (Object error, StackTrace stackTrace) {
......
......@@ -523,9 +523,13 @@ class HotRunner extends ResidentRunner {
// We ignore any errors, because it's not clear what we would do anyway.
futures.add(device.devFS!.destroy()
.timeout(const Duration(milliseconds: 250))
.catchError((Object? error) {
globals.printTrace('Ignored error while cleaning up DevFS: $error');
}));
.then<void>(
(Object? _) {},
onError: (Object? error, StackTrace stackTrace) {
globals.printTrace('Ignored error while cleaning up DevFS: $error\n$stackTrace');
}
),
);
}
device.devFS = null;
}
......@@ -639,16 +643,22 @@ class HotRunner extends ResidentRunner {
// Since we never check the value of this Future, only await its
// completion, make its type nullable so we can return null when
// catching errors.
.then<vm_service.Success?>((vm_service.Success success) => success)
.catchError((dynamic error, StackTrace stackTrace) {
// Do nothing on a SentinelException since it means the isolate
// has already been killed.
// Error code 105 indicates the isolate is not yet runnable, and might
// be triggered if the tool is attempting to kill the asset parsing
// isolate before it has finished starting up.
return null;
}, test: (dynamic error) => error is vm_service.SentinelException
|| (error is vm_service.RPCError && error.code == 105)));
.then<vm_service.Success?>(
(vm_service.Success success) => success,
onError: (Object error, StackTrace stackTrace) {
if (error is vm_service.SentinelException ||
(error is vm_service.RPCError && error.code == 105)) {
// Do nothing on a SentinelException since it means the isolate
// has already been killed.
// Error code 105 indicates the isolate is not yet runnable, and might
// be triggered if the tool is attempting to kill the asset parsing
// isolate before it has finished starting up.
return null;
}
return Future<vm_service.Success?>.error(error, stackTrace);
},
),
);
}
}
await Future.wait(operations);
......@@ -1309,10 +1319,16 @@ Future<ReassembleResult> _defaultReassembleHelper(
isolateId: view.uiIsolate!.id!,
);
}
reassembleFutures.add(reassembleWork.catchError((dynamic error) {
failedReassemble = true;
globals.printError('Reassembling ${view.uiIsolate!.name} failed: $error');
}, test: (dynamic error) => error is Exception));
reassembleFutures.add(reassembleWork.then(
(Object? obj) => obj,
onError: (Object error, StackTrace stackTrace) {
if (error is! Exception) {
return Future<Object?>.error(error, stackTrace);
}
failedReassemble = true;
globals.printError('Reassembling ${view.uiIsolate!.name} failed: $error\n$stackTrace');
},
));
}
}
}
......
......@@ -129,11 +129,16 @@ class CoverageCollector extends TestWatcher {
final Stopwatch? collectTestTimeRecorderStopwatch = testTimeRecorder?.start(TestTimePhases.CoverageCollect);
final Future<void> processComplete = testDevice.finished.catchError(
(Object error) => throw Exception(
'Failed to collect coverage, test device terminated prematurely with '
'error: ${(error as TestDeviceException).message}.'),
test: (Object error) => error is TestDeviceException,
final Future<void> processComplete = testDevice.finished.then(
(Object? obj) => obj,
onError: (Object error, StackTrace stackTrace) {
if (error is TestDeviceException) {
throw Exception(
'Failed to collect coverage, test device terminated prematurely with '
'error: ${error.message}.\n$stackTrace');
}
return Future<Object?>.error(error, stackTrace);
}
);
final Future<void> collectionComplete = testDevice.vmServiceUri
......
......@@ -680,25 +680,33 @@ class BrowserManager {
);
final Completer<BrowserManager> completer = Completer<BrowserManager>();
unawaited(chrome.onExit.then<Object?>((int? browserExitCode) {
throwToolExit('${runtime.name} exited with code $browserExitCode before connecting.');
}).catchError((Object error, StackTrace stackTrace) {
if (!completer.isCompleted) {
completer.completeError(error, stackTrace);
}
return null;
}));
unawaited(future.then((WebSocketChannel webSocket) {
if (completer.isCompleted) {
return;
}
completer.complete(BrowserManager._(chrome, runtime, webSocket));
}).catchError((Object error, StackTrace stackTrace) {
chrome.close();
if (!completer.isCompleted) {
completer.completeError(error, stackTrace);
}
}));
unawaited(chrome.onExit.then<Object?>(
(int? browserExitCode) {
throwToolExit('${runtime.name} exited with code $browserExitCode before connecting.');
},
).then(
(Object? obj) => obj,
onError: (Object error, StackTrace stackTrace) {
if (!completer.isCompleted) {
completer.completeError(error, stackTrace);
}
return null;
},
));
unawaited(future.then(
(WebSocketChannel webSocket) {
if (completer.isCompleted) {
return;
}
completer.complete(BrowserManager._(chrome, runtime, webSocket));
},
onError: (Object error, StackTrace stackTrace) {
chrome.close();
if (!completer.isCompleted) {
completer.completeError(error, stackTrace);
}
},
));
return completer.future;
}
......
......@@ -287,10 +287,17 @@ Future<vm_service.VmService> setUpVmService(
vmService.onExtensionEvent.listen(printStructuredErrorLogMethod);
registrationRequests.add(vmService
.streamListen(vm_service.EventStreams.kExtension)
.then<vm_service.Success?>((vm_service.Success success) => success)
// It is safe to ignore this error because we expect an error to be
// thrown if we're already subscribed.
.catchError((Object? error) => null, test: (Object? error) => error is vm_service.RPCError)
.then<vm_service.Success?>(
(vm_service.Success success) => success,
// It is safe to ignore this error because we expect an error to be
// thrown if we're already subscribed.
onError: (Object error, StackTrace stackTrace) {
if (error is vm_service.RPCError) {
return null;
}
return Future<vm_service.Success?>.error(error, stackTrace);
},
),
);
}
......@@ -971,14 +978,16 @@ class FlutterVmService {
/// been collected.
Future<vm_service.Isolate?> getIsolateOrNull(String isolateId) async {
return service.getIsolate(isolateId)
// The .then() call is required to cast from Future<Isolate> to Future<Isolate?>
.then<vm_service.Isolate?>((vm_service.Isolate isolate) => isolate)
.catchError((Object? error, StackTrace stackTrace) {
return null;
}, test: (Object? error) {
return (error is vm_service.SentinelException) ||
(error is vm_service.RPCError && error.code == RPCErrorCodes.kServiceDisappeared);
});
.then<vm_service.Isolate?>(
(vm_service.Isolate isolate) => isolate,
onError: (Object? error, StackTrace stackTrace) {
if (error is vm_service.SentinelException ||
error == null ||
(error is vm_service.RPCError && error.code == RPCErrorCodes.kServiceDisappeared)) {
return null;
}
return Future<vm_service.Isolate?>.error(error, stackTrace);
});
}
/// Create a new development file system on the device.
......
......@@ -164,9 +164,12 @@ void main() {
await FakeAsync().run((FakeAsync time) {
unawaited(runZonedGuarded(() async {
final Future<void> f = asyncGuard<void>(() => delayedThrow(time))
.catchError((Object e, StackTrace s) {
caughtByCatchError = true;
});
.then(
(Object? obj) => obj,
onError: (Object e, StackTrace s) {
caughtByCatchError = true;
},
);
try {
await f;
} on _CustomException {
......
......@@ -54,8 +54,8 @@ void main() {
final Set<int> completed = <int>{};
final TaskQueue<void> tracker = TaskQueue<void>(maxJobs: 1);
await tracker.add(() async => completed.add(0));
await tracker.add(() async => throw TestException()).catchError((Object _) {});
await tracker.add(() async => throw TestException()).catchError((Object _) {});
await tracker.add(() async => throw TestException()).then((_) {}, onError: (Object _) {});
await tracker.add(() async => throw TestException()).then((_) {}, onError: (Object _) {});
await tracker.add(() async => completed.add(3));
await tracker.tasksComplete;
expect(completed.length, equals(2));
......
......@@ -27,7 +27,10 @@ class DapTestClient {
vmServiceUri = event('dart.debuggerUris').then<Uri?>((Event event) {
final Map<String, Object?> body = event.body! as Map<String, Object?>;
return Uri.parse(body['vmServiceUri']! as String);
}).catchError((Object? e) => null);
}).then(
(Uri? uri) => uri,
onError: (Object? e) => null,
);
_subscription = _channel.listen(
_handleMessage,
......
......@@ -298,10 +298,13 @@ Future<ProcessTestResult> runFlutter(
}
process.stdin.write('q');
return -1; // discarded
}).catchError((Object error) {
// ignore errors here, they will be reported on the next line
return -1; // discarded
}));
}).then(
(int i) => i,
onError: (Object error) {
// ignore errors here, they will be reported on the next line
return -1; // discarded
},
));
final int exitCode = await process.exitCode;
if (streamingLogs) {
debugPrint('${stamp()} (process terminated with exit code $exitCode)');
......
......@@ -194,10 +194,13 @@ abstract class FlutterTestDriver {
// it forcefully and it won't terminate child processes, so we need to ensure
// it's running before terminating.
await resume().timeout(defaultTimeout)
.catchError((Object e) {
_debugPrint('Ignoring failure to resume during shutdown');
return null;
});
.then(
(Isolate? isolate) => isolate,
onError: (Object e) {
_debugPrint('Ignoring failure to resume during shutdown');
return null;
},
);
_debugPrint('Sending SIGTERM to $_processPid..');
io.Process.killPid(_processPid!);
......@@ -472,13 +475,16 @@ abstract class FlutterTestDriver {
});
final Future<T> future = callback().whenComplete(longWarning.cancel);
return future.catchError((Object error) {
if (!timeoutExpired) {
timeoutExpired = true;
_debugPrint(messages.toString());
}
throw error; // ignore: only_throw_errors
}).whenComplete(() => subscription.cancel());
return future.then(
(T t) => t,
onError: (Object error) {
if (!timeoutExpired) {
timeoutExpired = true;
_debugPrint(messages.toString());
}
throw error; // ignore: only_throw_errors
},
).whenComplete(() => subscription.cancel());
}
}
......
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