AnalysisDriver. Use AnalysisStatusAnalyzing to contain the 'idleCompleter'.

Change-Id: I155c2213624f87f415e11bda1ba1006660677f6e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347540
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2024-01-22 20:35:50 +00:00 committed by Commit Queue
parent e55af921ce
commit a3c115f9b0
3 changed files with 50 additions and 36 deletions

View file

@ -2187,7 +2187,7 @@ class AnalysisDriverScheduler {
/// Return `true` if we are currently analyzing code.
bool get isAnalyzing {
return _statusSupport.currentStatus == AnalysisStatus.ANALYZING;
return _statusSupport.currentStatus.isAnalyzing;
}
bool get isStarted => _started;

View file

@ -5,22 +5,35 @@
import 'dart:async';
/// The status of analysis.
class AnalysisStatus {
static const IDLE = AnalysisStatus._(false);
static const ANALYZING = AnalysisStatus._(true);
sealed class AnalysisStatus {
const AnalysisStatus._();
final bool _analyzing;
bool get isAnalyzing;
const AnalysisStatus._(this._analyzing);
bool get isIdle => !isAnalyzing;
}
/// Return `true` if the scheduler is analyzing.
bool get isAnalyzing => _analyzing;
final class AnalysisStatusAnalyzing extends AnalysisStatus {
/// Will complete when we switch to [AnalysisStatusIdle].
final Completer<void> _idleCompleter = Completer<void>();
/// Return `true` if the scheduler is idle.
bool get isIdle => !_analyzing;
AnalysisStatusAnalyzing._() : super._();
@override
String toString() => _analyzing ? 'analyzing' : 'idle';
bool get isAnalyzing => true;
@override
String toString() => 'analyzing';
}
final class AnalysisStatusIdle extends AnalysisStatus {
const AnalysisStatusIdle._() : super._();
@override
bool get isAnalyzing => false;
@override
String toString() => 'idle';
}
/// [Monitor] can be used to wait for a signal.
@ -54,11 +67,7 @@ class StatusSupport {
final _statusController = StreamController<AnalysisStatus>();
/// The last status sent to the [stream].
AnalysisStatus _currentStatus = AnalysisStatus.IDLE;
/// If non-null, a completer which should be completed on the next transition
/// to idle.
Completer<void>? _idleCompleter;
AnalysisStatus _currentStatus = const AnalysisStatusIdle._();
StatusSupport({
required StreamController<Object> eventsController,
@ -70,35 +79,40 @@ class StatusSupport {
/// Return the stream that produces [AnalysisStatus] events.
Stream<AnalysisStatus> get stream => _statusController.stream;
/// If the current status is not [AnalysisStatus.ANALYZING] yet, set the
/// If the current status is not [AnalysisStatusAnalyzing] yet, set the
/// current status to it, and send it to the stream.
void transitionToAnalyzing() {
if (_currentStatus != AnalysisStatus.ANALYZING) {
_idleCompleter = Completer<void>();
_currentStatus = AnalysisStatus.ANALYZING;
_eventsController.add(AnalysisStatus.ANALYZING);
_statusController.add(AnalysisStatus.ANALYZING);
if (_currentStatus is AnalysisStatusIdle) {
var newStatus = AnalysisStatusAnalyzing._();
_currentStatus = newStatus;
_eventsController.add(newStatus);
_statusController.add(newStatus);
}
}
/// If the current status is not [AnalysisStatus.IDLE] yet, set the
/// If the current status is not [AnalysisStatusIdle] yet, set the
/// current status to it, and send it to the stream.
void transitionToIdle() {
if (_currentStatus != AnalysisStatus.IDLE) {
_currentStatus = AnalysisStatus.IDLE;
_eventsController.add(AnalysisStatus.IDLE);
_statusController.add(AnalysisStatus.IDLE);
// TODO(scheglov): Use separate status classes?
_idleCompleter!.complete();
_idleCompleter = null;
if (_currentStatus case AnalysisStatusAnalyzing status) {
var newStatus = const AnalysisStatusIdle._();
_currentStatus = newStatus;
_eventsController.add(newStatus);
_statusController.add(newStatus);
status._idleCompleter.complete();
}
}
/// Return a future that will be completed the next time the status is idle.
/// If the current status is [AnalysisStatusIdle], returns the future that
/// will complete immediately.
///
/// If the status is currently idle, the returned future will be signaled
/// immediately.
/// If the current status is [AnalysisStatusAnalyzing], returns the future
/// that will complete when the status changes to [AnalysisStatusIdle].
Future<void> waitForIdle() {
return _idleCompleter?.future ?? Future<void>.value();
switch (_currentStatus) {
case AnalysisStatusIdle():
return Future<void>.value();
case AnalysisStatusAnalyzing status:
return status._idleCompleter.future;
}
}
}

View file

@ -258,9 +258,9 @@ class DriverEventsPrinter {
sink.writeIndentedLine(() {
sink.write('[status] ');
switch (event.status) {
case AnalysisStatus.ANALYZING:
case AnalysisStatusAnalyzing():
sink.write('analyzing');
case AnalysisStatus.IDLE:
case AnalysisStatusIdle():
sink.write('idle');
}
});