Skip to content

Commit 8f52a07

Browse files
bwilkersonCommit Queue
authored andcommitted
Send watch events through the message scheduler
If we need to control when requests that modify the state of analysis are performed, and we do, then that needs to include watch events from a file watcher. This CL causes those events to be placed on the message scheduler's queue so that we can control when we notify the analysis driver of changes. Change-Id: I1b099a35da7a4b9a6f4d86feb497d6822041155d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/421520 Reviewed-by: Phil Quitslund <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent 89593b3 commit 8f52a07

File tree

4 files changed

+71
-14
lines changed

4 files changed

+71
-14
lines changed

pkg/analysis_server/lib/src/analysis_server.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,8 +1062,6 @@ abstract class CommonServerContextManagerCallbacks
10621062

10631063
CommonServerContextManagerCallbacks(this.resourceProvider);
10641064

1065-
AnalysisServer get analysisServer;
1066-
10671065
@override
10681066
@mustCallSuper
10691067
void afterContextsCreated() {

pkg/analysis_server/lib/src/context_manager.dart

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import 'dart:async';
66
import 'dart:collection';
77

8+
import 'package:analysis_server/src/analysis_server.dart';
89
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
10+
import 'package:analysis_server/src/scheduler/scheduled_message.dart';
911
import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_parser.dart';
1012
import 'package:analyzer/dart/analysis/analysis_context.dart';
1113
import 'package:analyzer/dart/analysis/features.dart';
@@ -91,6 +93,9 @@ abstract class ContextManager {
9193
/// If no driver contains the given path, `null` is returned.
9294
AnalysisDriver? getDriverFor(String path);
9395

96+
/// Handle an [event] from a file watcher.
97+
void handleWatchEvent(WatchEvent event);
98+
9499
/// Return `true` if the file or directory with the given [path] will be
95100
/// analyzed in one of the analysis contexts.
96101
bool isAnalyzed(String path);
@@ -123,6 +128,9 @@ abstract class ContextManager {
123128
// operations return data structures describing how context state should be
124129
// modified.
125130
abstract class ContextManagerCallbacks {
131+
/// The analysis server that created this callback object.
132+
AnalysisServer get analysisServer;
133+
126134
/// Called after analysis contexts are created, usually when new analysis
127135
/// roots are set, or after detecting a change that required rebuilding
128136
/// the set of analysis contexts.
@@ -140,7 +148,7 @@ abstract class ContextManagerCallbacks {
140148
/// Sent the given watch [event] to any interested plugins.
141149
void broadcastWatchEvent(WatchEvent event);
142150

143-
/// Invoked on any [FileResult] in the analyzer events stream.
151+
/// Invoked on every [FileResult] in the analyzer events stream.
144152
void handleFileResult(FileResult result);
145153

146154
/// Add listeners to the [driver]. This must be the only listener.
@@ -309,6 +317,13 @@ class ContextManagerImpl implements ContextManager {
309317
return getContextFor(path)?.driver;
310318
}
311319

320+
@override
321+
void handleWatchEvent(WatchEvent event) {
322+
callbacks.broadcastWatchEvent(event);
323+
_handleWatchEvent(event);
324+
callbacks.afterWatchEvent(event);
325+
}
326+
312327
@override
313328
bool isAnalyzed(String path) {
314329
var collection = _collection;
@@ -610,7 +625,7 @@ class ContextManagerImpl implements ContextManager {
610625
watchers.add(watcher);
611626
watcherSubscriptions.add(
612627
watcher.changes.listen(
613-
_handleWatchEvent,
628+
_scheduleWatchEvent,
614629
onError: _handleWatchInterruption,
615630
),
616631
);
@@ -808,18 +823,14 @@ class ContextManagerImpl implements ContextManager {
808823
}
809824
}
810825

826+
/// Handle an [event] from a file watcher.
811827
void _handleWatchEvent(WatchEvent event) {
812-
callbacks.broadcastWatchEvent(event);
813-
_handleWatchEventImpl(event);
814-
callbacks.afterWatchEvent(event);
815-
}
816-
817-
void _handleWatchEventImpl(WatchEvent event) {
818828
// Figure out which context this event applies to.
819-
// TODO(brianwilkerson): If a file is explicitly included in one context
820-
// but implicitly referenced in another context, we will only send a
821-
// changeSet to the context that explicitly includes the file (because
822-
// that's the only context that's watching the file).
829+
//
830+
// If a file is explicitly included in one context but implicitly referenced
831+
// in another context, we will only notify the context that explicitly
832+
// includes the file (because that's the only context that's watching the
833+
// file).
823834
var path = event.path;
824835
var type = event.type;
825836

@@ -915,6 +926,15 @@ class ContextManagerImpl implements ContextManager {
915926
existingExcludedSet.containsAll(excludedPaths);
916927
}
917928

929+
/// Schedule the handling of a watch event.
930+
///
931+
/// This places the watch event on the message scheduler's queue so that it
932+
/// can be processed when we're not in the middle of handling some other
933+
/// message.
934+
void _scheduleWatchEvent(WatchEvent event) {
935+
callbacks.analysisServer.messageScheduler.add(WatcherMessage(event));
936+
}
937+
918938
/// Listens to files generated by Blaze that were found or searched for.
919939
///
920940
/// This is handled specially because the files are outside the package
@@ -941,6 +961,12 @@ class ContextManagerImpl implements ContextManager {
941961
}
942962

943963
class NoopContextManagerCallbacks implements ContextManagerCallbacks {
964+
@override
965+
AnalysisServer get analysisServer =>
966+
throw StateError(
967+
'The callback object should have been set by the server.',
968+
);
969+
944970
@override
945971
void afterContextsCreated() {}
946972

pkg/analysis_server/lib/src/scheduler/message_scheduler.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ final class MessageScheduler {
231231
message.responseCompleter,
232232
completer,
233233
);
234+
case WatcherMessage():
235+
server.contextManager.handleWatchEvent(message.event);
236+
// Handling a watch event is a synchronous process, so there's
237+
// nothing to wait for.
238+
completer.complete();
234239
}
235240

236241
// Blocking here with an await on the future was intended to prevent

pkg/analysis_server/lib/src/scheduler/scheduled_message.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,18 @@ import 'package:analysis_server/protocol/protocol.dart' as legacy;
99
import 'package:analyzer/src/util/performance/operation_performance.dart';
1010
import 'package:analyzer/src/utilities/cancellation.dart';
1111
import 'package:language_server_protocol/protocol_custom_generated.dart';
12+
import 'package:watcher/watcher.dart';
1213

1314
/// Represents a message from DTD (Dart Tooling Daemon).
1415
final class DtdMessage extends ScheduledMessage {
16+
/// The message that was received.
1517
final lsp.IncomingMessage message;
18+
19+
/// The completer to be signalled when a response to the message has been
20+
/// computed.
1621
final Completer<Map<String, Object?>> responseCompleter;
22+
23+
/// The object used to gather performance data.
1724
final OperationPerformanceImpl performance;
1825

1926
DtdMessage({
@@ -28,7 +35,11 @@ final class DtdMessage extends ScheduledMessage {
2835

2936
/// Represents a message in the Legacy protocol format.
3037
final class LegacyMessage extends ScheduledMessage {
38+
/// The Legacy message that was received.
3139
final legacy.Request request;
40+
41+
/// The token used to cancel the request, or `null` if the message is not a
42+
/// request.
3243
CancelableToken? cancellationToken;
3344

3445
LegacyMessage({required this.request, this.cancellationToken});
@@ -39,7 +50,11 @@ final class LegacyMessage extends ScheduledMessage {
3950

4051
/// Represents a message in the LSP protocol format.
4152
final class LspMessage extends ScheduledMessage {
53+
/// The LSP message that was received.
4254
final lsp.Message message;
55+
56+
/// The token used to cancel the request, or `null` if the message is not a
57+
/// request.
4358
CancelableToken? cancellationToken;
4459

4560
LspMessage({required this.message, this.cancellationToken});
@@ -64,3 +79,16 @@ final class LspMessage extends ScheduledMessage {
6479
///
6580
/// The client can be an IDE, a command-line tool, or DTD.
6681
sealed class ScheduledMessage {}
82+
83+
/// Represents a message from the file watcher.
84+
///
85+
/// This is always a notification.
86+
final class WatcherMessage extends ScheduledMessage {
87+
/// The event that was received.
88+
final WatchEvent event;
89+
90+
WatcherMessage(this.event);
91+
92+
@override
93+
String toString() => '${event.type} ${event.path}';
94+
}

0 commit comments

Comments
 (0)