0add39a68e
May prevent https://github.com/dart-lang/sdk/issues/48051 from occurring since we will no longer call driver.changeFile() for SDK libraries being opened, although it does not resolve the underlying issue. Change-Id: I5ca53a04842348a584ccc824aaf90ba7f230c002 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/251980 Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
215 lines
7.4 KiB
Dart
215 lines
7.4 KiB
Dart
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
|
import 'package:analysis_server/src/protocol/protocol_internal.dart';
|
|
import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Position;
|
|
import 'package:test/test.dart';
|
|
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
|
|
|
import 'server_abstract.dart';
|
|
|
|
void main() {
|
|
defineReflectiveSuite(() {
|
|
defineReflectiveTests(DocumentChangesTest);
|
|
});
|
|
}
|
|
|
|
@reflectiveTest
|
|
class DocumentChangesTest extends AbstractLspAnalysisServerTest {
|
|
String get content => '''
|
|
class Foo {
|
|
String get bar => 'baz';
|
|
}
|
|
''';
|
|
|
|
String get contentAfterUpdate => '''
|
|
class Bar {
|
|
String get bar => 'updated';
|
|
}
|
|
''';
|
|
|
|
Future<void> test_documentChange_notifiesPlugins() async {
|
|
await _initializeAndOpen();
|
|
await changeFile(2, mainFileUri, [
|
|
TextDocumentContentChangeEvent.t1(TextDocumentContentChangeEvent1(
|
|
range: Range(
|
|
start: Position(line: 0, character: 6),
|
|
end: Position(line: 0, character: 9)),
|
|
text: 'Bar',
|
|
)),
|
|
TextDocumentContentChangeEvent.t1(TextDocumentContentChangeEvent1(
|
|
range: Range(
|
|
start: Position(line: 1, character: 21),
|
|
end: Position(line: 1, character: 24)),
|
|
text: 'updated',
|
|
)),
|
|
]);
|
|
|
|
final notifiedChanges = pluginManager.analysisUpdateContentParams!
|
|
.files[mainFilePath] as ChangeContentOverlay;
|
|
|
|
expect(
|
|
applySequenceOfEdits(content, notifiedChanges.edits),
|
|
contentAfterUpdate,
|
|
);
|
|
}
|
|
|
|
Future<void> test_documentChange_updatesOverlay() async {
|
|
await _initializeAndOpen();
|
|
await changeFile(2, mainFileUri, [
|
|
TextDocumentContentChangeEvent.t1(TextDocumentContentChangeEvent1(
|
|
range: Range(
|
|
start: Position(line: 0, character: 6),
|
|
end: Position(line: 0, character: 9)),
|
|
text: 'Bar',
|
|
)),
|
|
TextDocumentContentChangeEvent.t1(TextDocumentContentChangeEvent1(
|
|
range: Range(
|
|
start: Position(line: 1, character: 21),
|
|
end: Position(line: 1, character: 24)),
|
|
text: 'updated',
|
|
)),
|
|
]);
|
|
|
|
expect(server.resourceProvider.hasOverlay(mainFilePath), isTrue);
|
|
expect(server.resourceProvider.getFile(mainFilePath).readAsStringSync(),
|
|
equals(contentAfterUpdate));
|
|
}
|
|
|
|
Future<void> test_documentClose_deletesOverlay() async {
|
|
await _initializeAndOpen();
|
|
await closeFile(mainFileUri);
|
|
|
|
expect(server.resourceProvider.hasOverlay(mainFilePath), isFalse);
|
|
}
|
|
|
|
Future<void> test_documentClose_notifiesPlugins() async {
|
|
await _initializeAndOpen();
|
|
await closeFile(mainFileUri);
|
|
|
|
expect(pluginManager.analysisUpdateContentParams!.files,
|
|
equals({mainFilePath: RemoveContentOverlay()}));
|
|
}
|
|
|
|
Future<void>
|
|
test_documentOpen_addsOverlayOnlyToDriver_onlyIfInsideRoots() async {
|
|
// Ensures that opening a file doesn't add it to the driver if it's outside
|
|
// of the drivers root.
|
|
final fileInsideRootPath = mainFilePath;
|
|
final fileOutsideRootPath = convertPath('/home/unrelated/main.dart');
|
|
await initialize();
|
|
await openFile(Uri.file(fileInsideRootPath), content);
|
|
await openFile(Uri.file(fileOutsideRootPath), content);
|
|
|
|
// Expect both files return the same driver
|
|
final driverForInside = server.getAnalysisDriver(fileInsideRootPath)!;
|
|
final driverForOutside = server.getAnalysisDriver(fileOutsideRootPath)!;
|
|
expect(driverForInside, equals(driverForOutside));
|
|
// But that only the file inside the root was added.
|
|
expect(driverForInside.addedFiles, contains(fileInsideRootPath));
|
|
expect(driverForInside.addedFiles, isNot(contains(fileOutsideRootPath)));
|
|
}
|
|
|
|
Future<void> test_documentOpen_contentChanged_analysis() async {
|
|
const content = '// original content';
|
|
const newContent = '// new content';
|
|
newFile(mainFilePath, content);
|
|
|
|
// Wait for initial analysis to provide diagnostics for the file.
|
|
await Future.wait([
|
|
waitForDiagnostics(mainFileUri),
|
|
initialize(),
|
|
]);
|
|
|
|
// Capture any further diagnostics sent after we open the file.
|
|
List<Diagnostic>? diagnostics;
|
|
unawaited(waitForDiagnostics(mainFileUri).then((d) => diagnostics = d));
|
|
await openFile(mainFileUri, newContent);
|
|
await pumpEventQueue(times: 5000);
|
|
|
|
// Expect diagnostics, because changing the content will have triggered
|
|
// analysis.
|
|
expect(diagnostics, isNotNull);
|
|
}
|
|
|
|
Future<void> test_documentOpen_contentUnchanged_noAnalysis() async {
|
|
const content = '// original content';
|
|
newFile(mainFilePath, content);
|
|
|
|
// Wait for initial analysis to provide diagnostics for the file.
|
|
await Future.wait([
|
|
waitForDiagnostics(mainFileUri),
|
|
initialize(),
|
|
]);
|
|
|
|
// Capture any further diagnostics sent after we open the file.
|
|
List<Diagnostic>? diagnostics;
|
|
unawaited(waitForDiagnostics(mainFileUri).then((d) => diagnostics = d));
|
|
await openFile(mainFileUri, content);
|
|
await pumpEventQueue(times: 5000);
|
|
|
|
// Expect no diagnostics because the file didn't actually change content
|
|
// when the overlay was created, so it should not have triggered analysis.
|
|
expect(diagnostics, isNull);
|
|
}
|
|
|
|
Future<void> test_documentOpen_createsOverlay() async {
|
|
await _initializeAndOpen();
|
|
|
|
expect(server.resourceProvider.hasOverlay(mainFilePath), isTrue);
|
|
expect(server.resourceProvider.getFile(mainFilePath).readAsStringSync(),
|
|
equals(content));
|
|
}
|
|
|
|
Future<void> test_documentOpen_notifiesPlugins() async {
|
|
await _initializeAndOpen();
|
|
|
|
expect(pluginManager.analysisUpdateContentParams!.files,
|
|
equals({mainFilePath: AddContentOverlay(content)}));
|
|
}
|
|
|
|
Future<void> test_documentOpen_setsPriorityFileIfEarly() async {
|
|
// When initializing with config support, the server will call back to the client
|
|
// which can delay analysis roots being configured. This can result in files
|
|
// being opened before analysis roots are set which has previously caused the
|
|
// files not to be marked as priority on the created drivers.
|
|
// https://github.com/Dart-Code/Dart-Code/issues/2438
|
|
// https://github.com/dart-lang/sdk/issues/42994
|
|
|
|
// Initialize the server, but delay providing the configuration until after
|
|
// we've opened the file.
|
|
final completer = Completer<void>();
|
|
|
|
// Send the initialize request but do not await it.
|
|
final initResponse = initialize(
|
|
workspaceCapabilities: withDidChangeConfigurationDynamicRegistration(
|
|
withConfigurationSupport(emptyWorkspaceClientCapabilities)));
|
|
|
|
// When asked for config, delay the response until we have sent the openFile notification.
|
|
final config = provideConfig(
|
|
() => initResponse,
|
|
completer.future.then((_) => {'dart.foo': false}),
|
|
);
|
|
|
|
// Wait for initialization to finish, open the file, then allow config to complete.
|
|
await initResponse;
|
|
await openFile(mainFileUri, content);
|
|
completer.complete();
|
|
await config;
|
|
await pumpEventQueue(times: 5000);
|
|
|
|
// Ensure the opened file is in the priority list.
|
|
expect(server.getAnalysisDriver(mainFilePath)!.priorityFiles,
|
|
equals([mainFilePath]));
|
|
}
|
|
|
|
Future<void> _initializeAndOpen() async {
|
|
await initialize();
|
|
await openFile(mainFileUri, content);
|
|
}
|
|
}
|