Basic implementation of MOVE_FILE for files
Simple file tests are passing (directories, packages still outstanding).
Bug: https://github.com/dart-lang/sdk/issues/33605
Change-Id: Id9793698050c1a98ad56f511bb515d59d6c769ca
Reviewed-on: https://dart-review.googlesource.com/63740
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Danny Tuppeny <dantup@google.com>
diff --git a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
index d6d56db..58adda3 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
@@ -9,9 +9,11 @@
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
+import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
import 'package:path/path.dart' as pathos;
/**
@@ -27,11 +29,6 @@
String oldFile;
String newFile;
- SourceChange change;
- LibraryElement library;
- String oldLibraryDir;
- String newLibraryDir;
-
MoveFileRefactoringImpl(ResourceProvider resourceProvider, this.workspace,
this.source, this.oldFile)
: resourceProvider = resourceProvider,
@@ -58,8 +55,47 @@
@override
Future<SourceChange> createChange() async {
- // TODO(dantup): Implement!
- return new SourceChange('Update File References');
+ var changeBuilder =
+ new DartChangeBuilder(workspace.drivers.first.currentSession);
+
+ final drivers =
+ workspace.drivers.where((d) => d.contextRoot.containsFile(newFile));
+ if (drivers.length != 1) {
+ // TODO(dantup): What to do in this case? Should we throw?
+ return changeBuilder.sourceChange;
+ }
+
+ final driver = drivers.first; // The above guarantees there's exactly one.
+ final result = await driver.getResult(oldFile);
+ final element = result?.unit?.element;
+ if (element == null) {
+ return changeBuilder.sourceChange;
+ }
+ final library = element.library;
+
+ // If this element is a library, update outgoing references inside the file.
+ if (library != null && element == library.definingCompilationUnit) {
+ await changeBuilder.addFileEdit(library.source.fullName, (builder) {
+ final oldDir = pathContext.dirname(oldFile);
+ final newDir = pathContext.dirname(newFile);
+ _updateUriReferences(builder, library.imports, oldDir, newDir);
+ _updateUriReferences(builder, library.exports, oldDir, newDir);
+ _updateUriReferences(builder, library.parts, oldDir, newDir);
+ });
+ }
+
+ // Update incoming references to this file
+ List<SearchMatch> matches =
+ await workspace.searchEngine.searchReferences(result.unit.element);
+ List<SourceReference> references = getSourceReferences(matches);
+ for (SourceReference reference in references) {
+ await changeBuilder.addFileEdit(reference.file, (builder) {
+ String newUri = _computeNewUri(reference);
+ builder.addSimpleReplacement(reference.range, "'$newUri'");
+ });
+ }
+
+ return changeBuilder.sourceChange;
}
@override
@@ -91,23 +127,43 @@
return true;
}
- void _updateUriReference(UriReferencedElement element) {
+ void _updateUriReference(DartFileEditBuilder builder,
+ UriReferencedElement element, String oldDir, String newDir) {
if (!element.isSynthetic) {
String elementUri = element.uri;
if (_isRelativeUri(elementUri)) {
- String elementPath = pathContext.join(oldLibraryDir, elementUri);
- String newUri = _getRelativeUri(elementPath, newLibraryDir);
+ String elementPath = pathContext.join(oldDir, elementUri);
+ String newUri = _getRelativeUri(elementPath, newDir);
int uriOffset = element.uriOffset;
int uriLength = element.uriEnd - uriOffset;
- doSourceChange_addElementEdit(
- change, library, new SourceEdit(uriOffset, uriLength, "'$newUri'"));
+ builder.addSimpleReplacement(
+ new SourceRange(uriOffset, uriLength), "'$newUri'");
}
}
}
- void _updateUriReferences(List<UriReferencedElement> elements) {
+ void _updateUriReferences(DartFileEditBuilder builder,
+ List<UriReferencedElement> elements, String oldDir, String newDir) {
for (UriReferencedElement element in elements) {
- _updateUriReference(element);
+ _updateUriReference(builder, element, oldDir, newDir);
}
}
+
+ /**
+ * Computes the URI to use to reference [newFile] from [reference].
+ */
+ String _computeNewUri(SourceReference reference) {
+ String refDir = pathContext.dirname(reference.file);
+ // try to keep package: URI
+ // if (_isPackageReference(reference)) {
+ // Source newSource = new NonExistingSource(
+ // newFile, pathos.toUri(newFile), UriKind.FILE_URI);
+ // Uri restoredUri = context.sourceFactory.restoreUri(newSource);
+ // if (restoredUri != null) {
+ // return restoredUri.toString();
+ // }
+ // }
+ // if no package: URI, prepare relative
+ return _getRelativeUri(newFile, refDir);
+ }
}
diff --git a/pkg/analysis_server/test/services/refactoring/move_file_test.dart b/pkg/analysis_server/test/services/refactoring/move_file_test.dart
index d2dd25d..72f5b4b 100644
--- a/pkg/analysis_server/test/services/refactoring/move_file_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/move_file_test.dart
@@ -20,7 +20,6 @@
class MoveFileTest extends RefactoringTest {
MoveFileRefactoring refactoring;
- @failingTest
test_file_containing_imports_exports_parts() async {
String pathA = '/project/000/1111/a.dart';
String pathB = '/project/000/1111/b.dart';
@@ -135,7 +134,6 @@
assertNoFileChange(testFile);
}
- @failingTest
test_file_referenced_by_part() async {
String pathA = '/project/000/1111/a.dart';
testFile = '/project/000/1111/22/test.dart';
@@ -187,6 +185,14 @@
}
@failingTest
+ test_renaming_part_that_uses_uri_in_part_of() async {
+ // If the file is a part in a library, and the part-of directive uses a URI
+ // rather than a library name, that will need updating too (if the relative
+ // path to the parent changes).
+ fail('Not yet implemented/tested');
+ }
+
+ @failingTest
test_projectFolder() async {
fail('Not yet implemented/tested');
}
@@ -197,10 +203,27 @@
}
@failingTest
+ test_folder_outside_workspace_returns_failure() async {
+ fail('Not yet implemented/tested');
+ }
+
+ @failingTest
test_project_folder_ancestor() async {
fail('Not yet implemented/tested');
}
+ @failingTest
+ test_nonexistent_file_returns_suitable_failure() async {
+ fail('Not yet implemented/tested');
+ }
+
+ @failingTest
+ test_dart_uris_are_unmodified() async {
+ // TODO(dantup): See _computeNewUri implementation which currently only
+ // handles relative + package: urls (package url handling is also incomplete)
+ fail('Not yet implemented/tested');
+ }
+
/**
* Checks that all conditions are OK.
*/