Skip to content

Commit c6a82eb

Browse files
scheglovCommit Queue
authored and
Commit Queue
committed
Macro. Send dart/textDocumentContentDidChange before analysis.errors
Change-Id: I343d61208f3500e68219257459e167307a55ee78 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360662 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 5543d88 commit c6a82eb

File tree

4 files changed

+166
-18
lines changed

4 files changed

+166
-18
lines changed

pkg/analysis_server/lib/src/analysis_server.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -999,18 +999,6 @@ abstract class CommonServerContextManagerCallbacks
999999
var path = result.path;
10001000
filesToFlush.add(path);
10011001

1002-
if (result is AnalysisResultWithErrors) {
1003-
if (analysisServer.isAnalyzed(path)) {
1004-
final serverErrors = server.doAnalysisError_listFromEngine(result);
1005-
recordAnalysisErrors(path, serverErrors);
1006-
}
1007-
}
1008-
1009-
if (result is ResolvedUnitResult) {
1010-
analysisServer.filesResolvedSinceLastIdle.add(path);
1011-
handleResolvedUnitResult(result);
1012-
}
1013-
10141002
// If this is a virtual file and the client supports URIs, we need to notify
10151003
// that it's been updated.
10161004
var lspUri = analysisServer.uriConverter.toClientUri(result.path);
@@ -1027,6 +1015,18 @@ abstract class CommonServerContextManagerCallbacks
10271015
);
10281016
analysisServer.sendLspNotification(message);
10291017
}
1018+
1019+
if (result is AnalysisResultWithErrors) {
1020+
if (analysisServer.isAnalyzed(path)) {
1021+
final serverErrors = server.doAnalysisError_listFromEngine(result);
1022+
recordAnalysisErrors(path, serverErrors);
1023+
}
1024+
}
1025+
1026+
if (result is ResolvedUnitResult) {
1027+
analysisServer.filesResolvedSinceLastIdle.add(path);
1028+
handleResolvedUnitResult(result);
1029+
}
10301030
}
10311031

10321032
void handleResolvedUnitResult(ResolvedUnitResult result);

pkg/analysis_server/test/analysis_server_base.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ abstract class ContextResolutionTest with ResourceProviderMixin {
9393
final List<GeneralAnalysisService> _analysisGeneralServices = [];
9494
final Map<AnalysisService, List<String>> _analysisFileSubscriptions = {};
9595

96+
void Function(Notification)? notificationListener;
97+
9698
Folder get sdkRoot => newFolder('/sdk');
9799

98100
Future<void> addGeneralAnalysisSubscription(
@@ -126,7 +128,9 @@ abstract class ContextResolutionTest with ResourceProviderMixin {
126128
return response;
127129
}
128130

129-
void processNotification(Notification notification) {}
131+
void processNotification(Notification notification) {
132+
notificationListener?.call(notification);
133+
}
130134

131135
Future<void> removeGeneralAnalysisSubscription(
132136
GeneralAnalysisService service,

pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,114 @@ import 'dart:convert';
77

88
import 'package:analysis_server/lsp_protocol/protocol.dart';
99
import 'package:analysis_server/protocol/protocol_constants.dart';
10+
import 'package:analysis_server/src/lsp/constants.dart';
1011
import 'package:analysis_server/src/protocol/protocol_internal.dart';
1112
import 'package:analysis_server/src/protocol_server.dart';
13+
import 'package:analyzer/file_system/file_system.dart';
14+
import 'package:analyzer/src/utilities/extensions/file_system.dart';
1215
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
16+
import 'package:collection/collection.dart';
1317
import 'package:path/path.dart' as path;
1418
import 'package:test/test.dart';
1519

1620
import '../analysis_server_base.dart';
1721
import '../lsp/change_verifier.dart';
1822
import '../lsp/request_helpers_mixin.dart';
23+
import '../services/completion/dart/text_expectations.dart';
24+
import '../utils/tree_string_sink.dart';
25+
26+
class EventsCollector {
27+
final ContextResolutionTest test;
28+
List<Object> events = [];
29+
30+
EventsCollector(this.test) {
31+
test.notificationListener = (notification) {
32+
switch (notification.event) {
33+
case ANALYSIS_NOTIFICATION_ERRORS:
34+
events.add(
35+
AnalysisErrorsParams.fromNotification(notification),
36+
);
37+
case ANALYSIS_NOTIFICATION_FLUSH_RESULTS:
38+
events.add(
39+
AnalysisFlushResultsParams.fromNotification(notification),
40+
);
41+
case LSP_NOTIFICATION_NOTIFICATION:
42+
final params = LspNotificationParams.fromNotification(notification);
43+
events.add(params.lspNotification);
44+
default:
45+
throw StateError(notification.event);
46+
}
47+
};
48+
}
49+
50+
List<Object> take() {
51+
final result = events;
52+
events = [];
53+
return result;
54+
}
55+
}
56+
57+
class EventsPrinter {
58+
final EventsPrinterConfiguration configuration;
59+
final ResourceProvider resourceProvider;
60+
final TreeStringSink sink;
61+
62+
EventsPrinter({
63+
required this.configuration,
64+
required this.resourceProvider,
65+
required this.sink,
66+
});
67+
68+
void write(List<Object> events) {
69+
for (final event in events) {
70+
switch (event) {
71+
case AnalysisErrorsParams():
72+
sink.writelnWithIndent('AnalysisErrors');
73+
sink.withIndent(() {
74+
_writelnFile(name: 'file', event.file);
75+
if (event.errors.isNotEmpty) {
76+
sink.writelnWithIndent('errors: notEmpty');
77+
} else {
78+
sink.writelnWithIndent('errors: empty');
79+
}
80+
});
81+
case AnalysisFlushResultsParams():
82+
sink.writeElements(
83+
'AnalysisFlushResults',
84+
event.files.sorted(),
85+
_writelnFile,
86+
);
87+
case NotificationMessage():
88+
switch (event.method) {
89+
case CustomMethods.dartTextDocumentContentDidChange:
90+
sink.writelnWithIndent(event.method);
91+
var params =
92+
event.params as DartTextDocumentContentDidChangeParams;
93+
sink.withIndent(() {
94+
sink.writeIndentedLine(() {
95+
sink.write('uri: ');
96+
sink.write(params.uri);
97+
});
98+
});
99+
}
100+
default:
101+
throw UnimplementedError('${event.runtimeType}');
102+
}
103+
}
104+
}
105+
106+
void _writelnFile(String path, {String? name}) {
107+
sink.writeIndentedLine(() {
108+
if (name != null) {
109+
sink.write('$name: ');
110+
}
111+
final file = resourceProvider.getFile(path);
112+
sink.write(file.posixPath);
113+
});
114+
}
115+
}
116+
117+
class EventsPrinterConfiguration {}
19118

20119
abstract class LspOverLegacyTest extends PubPackageAnalysisServerTest
21120
with
@@ -61,6 +160,31 @@ abstract class LspOverLegacyTest extends PubPackageAnalysisServerTest
61160
);
62161
}
63162

163+
Future<void> assertEventsText(
164+
EventsCollector collector,
165+
String expected,
166+
) async {
167+
await pumpEventQueue(times: 5000);
168+
169+
final buffer = StringBuffer();
170+
final sink = TreeStringSink(sink: buffer, indent: '');
171+
172+
final events = collector.take();
173+
EventsPrinter(
174+
configuration: EventsPrinterConfiguration(),
175+
resourceProvider: resourceProvider,
176+
sink: sink,
177+
).write(events);
178+
179+
final actual = buffer.toString();
180+
if (actual != expected) {
181+
print('-------- Actual --------');
182+
print('$actual------------------------');
183+
TextExpectationsCollector.add(actual);
184+
}
185+
expect(actual, expected);
186+
}
187+
64188
/// Creates a legacy request with an auto-assigned ID.
65189
Request createLegacyRequest(RequestParams params) {
66190
return params.toRequest('${_nextLspRequestId++}');

pkg/analysis_server/test/lsp_over_legacy/dart_text_document_content_provider_test.dart

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:analysis_server/protocol/protocol_generated.dart';
5+
import 'package:analysis_server/src/protocol_server.dart';
66
import 'package:test/test.dart';
77
import 'package:test_reflective_loader/test_reflective_loader.dart';
88

@@ -65,15 +65,35 @@ class A {}
6565
await waitForTasksFinished();
6666
await enableCustomUriSupport();
6767

68+
final collector = EventsCollector(this);
69+
6870
// Verify initial contents of the macro.
6971
var macroGeneratedContent =
7072
await getDartTextDocumentContent(testFileMacroUri);
7173
expect(macroGeneratedContent!.content, contains('void foo() {'));
7274

73-
// Modify the file and expect a change event.
74-
newFile(testFilePath, content.replaceAll('void foo() {', 'void foo2() {'));
75-
await dartTextDocumentContentDidChangeNotifications
76-
.firstWhere((notification) => notification.uri == testFileMacroUri);
75+
// Modify the file, changing its API signature.
76+
// So, the macro runs, and the macro generated file changes.
77+
newFile(
78+
testFilePath,
79+
content.replaceAll(
80+
'void foo() {}',
81+
'void foo2() {}',
82+
),
83+
);
84+
85+
// Note, 'dart/textDocumentContentDidChange' before 'AnalysisErrors'.
86+
// So, the IDE does not discard errors.
87+
await assertEventsText(collector, r'''
88+
AnalysisErrors
89+
file: /home/test/lib/test.dart
90+
errors: empty
91+
dart/textDocumentContentDidChange
92+
uri: dart-macro+file:///home/test/lib/test.dart
93+
AnalysisErrors
94+
file: /home/test/lib/test.macro.dart
95+
errors: empty
96+
''');
7797

7898
// Verify updated contents of the macro.
7999
macroGeneratedContent = await getDartTextDocumentContent(testFileMacroUri);

0 commit comments

Comments
 (0)