Replace DartFileEditBuilder.importLibraries() with importLibrary().

It now returns the text of the URI that will be actually used, so
we can show it in the quick fix message without computing it separately.

R=brianwilkerson@google.com

Change-Id: I16a455d8f6a3c3e3a9c5779c94d654de32992006
Reviewed-on: https://dart-review.googlesource.com/55501
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 3ffcc35..f83778d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1955,13 +1955,13 @@
     _addFixFromBuilder(changeBuilder, DartFixKind.REPLACE_RETURN_TYPE_FUTURE);
   }
 
-  Future<Null> _addFix_importLibrary(FixKind kind, Source library) async {
-    String libraryUri = getLibrarySourceUri(unitLibraryElement, library);
+  Future<Null> _addFix_importLibrary(FixKind kind, Uri library) async {
+    String uriText;
     DartChangeBuilder changeBuilder = new DartChangeBuilder(session);
     await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-      builder.importLibraries([library]);
+      uriText = builder.importLibrary(library);
     });
-    _addFixFromBuilder(changeBuilder, kind, args: [libraryUri]);
+    _addFixFromBuilder(changeBuilder, kind, args: [uriText]);
   }
 
   Future<Null> _addFix_importLibrary_withElement(String name,
@@ -2061,7 +2061,7 @@
           fixKind = DartFixKind.IMPORT_LIBRARY_PROJECT1;
         }
         // Add the fix.
-        await _addFix_importLibrary(fixKind, librarySource);
+        await _addFix_importLibrary(fixKind, librarySource.uri);
       }
     }
   }
@@ -2821,7 +2821,8 @@
 
   Future<Null> _addFix_undefinedFunction_create() async {
     // should be the name of the invocation
-    if (node is SimpleIdentifier && node.parent is MethodInvocation) {} else {
+    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+    } else {
       return;
     }
     String name = (node as SimpleIdentifier).name;
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 5878f8c..d5bd83e 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -21,14 +21,14 @@
     show SourceChange, SourceEdit;
 import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
-import 'package:path/path.dart';
+import 'package:path/path.dart' as pathos;
 
 /**
  * Adds edits to the given [change] that ensure that all the [libraries] are
  * imported into the given [targetLibrary].
  */
-void addLibraryImports(
-    SourceChange change, LibraryElement targetLibrary, Set<Source> libraries) {
+void addLibraryImports(pathos.Context pathContext, SourceChange change,
+    LibraryElement targetLibrary, Set<Source> libraries) {
   CorrectionUtils libUtils;
   try {
     CompilationUnitElement unitElement = targetLibrary.definingCompilationUnit;
@@ -52,7 +52,8 @@
 
   // Prepare all URIs to import.
   List<String> uriList = libraries
-      .map((library) => getLibrarySourceUri(targetLibrary, library))
+      .map((library) =>
+          getLibrarySourceUri(pathContext, targetLibrary, library.uri))
       .toList();
   uriList.sort((a, b) => a.compareTo(b));
 
@@ -347,18 +348,14 @@
 /**
  * Computes the best URI to import [what] into [from].
  */
-String getLibrarySourceUri(LibraryElement from, Source what) {
-  String whatPath = what.fullName;
-  // check if an absolute URI (such as 'dart:' or 'package:')
-  Uri whatUri = what.uri;
-  String whatUriScheme = whatUri.scheme;
-  if (whatUriScheme != '' && whatUriScheme != 'file') {
-    return whatUri.toString();
+String getLibrarySourceUri(
+    pathos.Context pathContext, LibraryElement from, Uri what) {
+  if (what.scheme == 'file') {
+    String fromFolder = pathContext.dirname(from.source.fullName);
+    String relativeFile = pathContext.relative(what.path, from: fromFolder);
+    return pathContext.split(relativeFile).join('/');
   }
-  // compute a relative URI
-  String fromFolder = dirname(from.source.fullName);
-  String relativeFile = relative(whatPath, from: fromFolder);
-  return split(relativeFile).join('/');
+  return what.toString();
 }
 
 /**
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index c1ce1cb..4a1d37a 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -389,7 +389,8 @@
       }
     }
     // done
-    addLibraryImports(change, libraryElement, librariesToImport);
+    addLibraryImports(session.resourceProvider.pathContext, change,
+        libraryElement, librariesToImport);
     return change;
   }
 
diff --git a/pkg/analysis_server/test/services/correction/util_test.dart b/pkg/analysis_server/test/services/correction/util_test.dart
index 05866c9..3e1981c 100644
--- a/pkg/analysis_server/test/services/correction/util_test.dart
+++ b/pkg/analysis_server/test/services/correction/util_test.dart
@@ -287,7 +287,8 @@
 
   void _assertAddLibraryImport(List<Source> newLibraries, String expectedCode) {
     SourceChange change = new SourceChange('');
-    addLibraryImports(change, testLibraryElement, newLibraries.toSet());
+    addLibraryImports(resourceProvider.pathContext, change, testLibraryElement,
+        newLibraries.toSet());
     SourceFileEdit testEdit = change.getFileEdit(testFile);
     expect(testEdit, isNotNull);
     String resultCode = SourceEdit.applySequence(testCode, testEdit.edits);
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index b9b3f80..06e9aaa 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -24,7 +24,6 @@
 import 'package:analyzer_plugin/utilities/range_factory.dart';
 import 'package:charcode/ascii.dart';
 import 'package:meta/meta.dart';
-import 'package:path/path.dart' as path;
 
 /**
  * A [ChangeBuilder] used to build changes in Dart files.
@@ -91,8 +90,8 @@
   /**
    * Arrange to have an import added for the given [library].
    */
-  void importLibrary(Source library) {
-    dartFileEditBuilder.librariesToImport.add(library);
+  void importLibrary(Uri library) {
+    dartFileEditBuilder.importLibrary(library);
   }
 
   @override
@@ -596,7 +595,7 @@
           write('.');
         }
       } else {
-        importLibrary(definingLibrary.source);
+        importLibrary(definingLibrary.source.uri);
       }
     }
 
@@ -1022,7 +1021,7 @@
           buffer.write(".");
         }
       } else {
-        importLibrary(definingLibrary.source);
+        importLibrary(definingLibrary.source.uri);
       }
     }
     // append simple name
@@ -1182,10 +1181,10 @@
   CompilationUnit unit;
 
   /**
-   * A set containing the sources of the libraries that need to be imported in
-   * order to make visible the names used in generated code.
+   * The set of absolute or relative URIs of the libraries that need to be
+   * imported in order to make visible the names used in generated code.
    */
-  Set<Source> librariesToImport = new Set<Source>();
+  Set<String> librariesToImport = new Set<String>();
 
   /**
    * Initialize a newly created builder to build a source file edit within the
@@ -1231,20 +1230,23 @@
       CompilationUnitElement definingUnitElement =
           libraryElement.definingCompilationUnit;
       if (definingUnitElement == unitElement) {
-        _addLibraryImports(libraryElement, librariesToImport);
+        _addLibraryImports(librariesToImport);
       } else {
         await (changeBuilder as DartChangeBuilder).addFileEdit(
             definingUnitElement.source.fullName, (DartFileEditBuilder builder) {
           (builder as DartFileEditBuilderImpl)
-              ._addLibraryImports(libraryElement, librariesToImport);
+              ._addLibraryImports(librariesToImport);
         });
       }
     }
   }
 
   @override
-  void importLibraries(Iterable<Source> libraries) {
-    librariesToImport.addAll(libraries);
+  String importLibrary(Uri library) {
+    LibraryElement targetLibrary = unit.element.library;
+    String uriText = _getLibrarySourceUri(targetLibrary, library);
+    librariesToImport.add(uriText);
+    return uriText;
   }
 
   @override
@@ -1274,10 +1276,9 @@
   }
 
   /**
-   * Adds edits ensure that all the [libraries] are imported into the given
-   * [targetLibrary].
+   * Adds edits ensure that all the [libraries] are imported.
    */
-  void _addLibraryImports(LibraryElement targetLibrary, Set<Source> libraries) {
+  void _addLibraryImports(Set<String> libraries) {
     // Prepare information about existing imports.
     LibraryDirective libraryDirective;
     List<ImportDirective> importDirectives = <ImportDirective>[];
@@ -1290,9 +1291,7 @@
     }
 
     // Prepare all URIs to import.
-    List<String> uriList = libraries
-        .map((library) => _getLibrarySourceUri(targetLibrary, library))
-        .toList();
+    List<String> uriList = libraries.toList();
     uriList.sort((a, b) => a.compareTo(b));
 
     // Insert imports: between existing imports.
@@ -1449,18 +1448,15 @@
   /**
    * Computes the best URI to import [what] into [from].
    */
-  String _getLibrarySourceUri(LibraryElement from, Source what) {
-    String whatPath = what.fullName;
-    // check if an absolute URI (such as 'dart:' or 'package:')
-    Uri whatUri = what.uri;
-    String whatUriScheme = whatUri.scheme;
-    if (whatUriScheme != '' && whatUriScheme != 'file') {
-      return whatUri.toString();
+  String _getLibrarySourceUri(LibraryElement from, Uri what) {
+    if (what.scheme == 'file') {
+      var session = (changeBuilder as DartChangeBuilderImpl).session;
+      var pathContext = session.resourceProvider.pathContext;
+      String fromFolder = pathContext.dirname(from.source.fullName);
+      String relativeFile = pathContext.relative(what.path, from: fromFolder);
+      return pathContext.split(relativeFile).join('/');
     }
-    // compute a relative URI
-    String fromFolder = path.dirname(from.source.fullName);
-    String relativeFile = path.relative(whatPath, from: fromFolder);
-    return path.split(relativeFile).join('/');
+    return what.toString();
   }
 
   /**
diff --git a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
index f1f68be..3f24874 100644
--- a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
@@ -305,9 +305,12 @@
       FunctionBody body, TypeProvider typeProvider);
 
   /**
-   * Arrange to have imports added for each of the given [libraries].
+   * Arrange to have an import added for the given [library].
+   *
+   * Returns the text of the URI that will be used in the import directive.
+   * It can be different than the given [Uri].
    */
-  void importLibraries(Iterable<Source> libraries);
+  String importLibrary(Uri library);
 
   /**
    * Optionally create an edit to replace the given [typeAnnotation] with the
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index d8d76f8..d0dfbc4 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -74,7 +74,7 @@
 class DartEditBuilderImplTest extends AbstractContextTest
     with BuilderTestMixin {
   test_importLibraries_DP() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'dart:aaa';
 import 'dart:ccc';
 
@@ -92,7 +92,7 @@
   }
 
   test_importLibraries_PD() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'dart:aaa';
 import 'dart:ccc';
 
@@ -110,7 +110,7 @@
   }
 
   test_importLibrary_afterLibraryDirective_dart() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 library test;
 
 class A {}
@@ -125,7 +125,7 @@
   }
 
   test_importLibrary_dart_beforeDart() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'dart:aaa';
 import 'dart:ccc';
 ''', ['dart:bbb'], '''
@@ -136,7 +136,7 @@
   }
 
   test_importLibrary_dart_beforeDart_first() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'dart:bbb';
 ''', ['dart:aaa'], '''
 import 'dart:aaa';
@@ -145,7 +145,7 @@
   }
 
   test_importLibrary_dart_beforePackage() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'package:foo/foo.dart';
 ''', ['dart:async'], '''
 import 'dart:async';
@@ -155,7 +155,7 @@
   }
 
   test_importLibrary_noDirectives_docComment() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 /// Documentation comment.
 /// Continues.
 void main() {}
@@ -169,7 +169,7 @@
   }
 
   test_importLibrary_noDirectives_hashBang() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 #!/bin/dart
 
 void main() {}
@@ -183,7 +183,7 @@
   }
 
   test_importLibrary_noDirectives_lineComment() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 // Not documentation comment.
 // Continues.
 
@@ -199,7 +199,7 @@
   }
 
   test_importLibrary_package_afterDart() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'dart:async';
 ''', ['package:aaa/aaa.dart'], '''
 import 'dart:async';
@@ -209,7 +209,7 @@
   }
 
   test_importLibrary_package_afterPackage() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'package:aaa/a1.dart';
 
 import 'foo.dart';
@@ -222,7 +222,7 @@
   }
 
   test_importLibrary_package_afterPackage_leadingComment() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 // comment
 import 'package:aaa/a1.dart';
 
@@ -237,7 +237,7 @@
   }
 
   test_importLibrary_package_afterPackage_trailingComment() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'package:aaa/a1.dart'; // comment
 
 import 'foo.dart';
@@ -250,7 +250,7 @@
   }
 
   test_importLibrary_package_beforePackage() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'package:aaa/a1.dart';
 import 'package:aaa/a3.dart';
 
@@ -265,7 +265,7 @@
   }
 
   test_importLibrary_package_beforePackage_first() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'package:aaa/a2.dart';
 
 import 'foo.dart';
@@ -278,7 +278,7 @@
   }
 
   test_importLibrary_package_beforePackage_leadingComments() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 // comment a2
 import 'package:aaa/a2.dart';
 
@@ -293,7 +293,7 @@
   }
 
   test_importLibrary_package_beforePackage_trailingComments() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'package:aaa/a2.dart'; // comment a2
 
 import 'foo.dart';
@@ -306,7 +306,7 @@
   }
 
   test_importLibrary_package_beforeRelative() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'foo.dart';
 ''', ['package:aaa/aaa.dart'], '''
 import 'package:aaa/aaa.dart';
@@ -316,7 +316,7 @@
   }
 
   test_importLibrary_relative_afterDart() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'dart:async';
 ''', ['aaa.dart'], '''
 import 'dart:async';
@@ -326,7 +326,7 @@
   }
 
   test_importLibrary_relative_afterPackage() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'package:foo/foo.dart';
 ''', ['aaa.dart'], '''
 import 'package:foo/foo.dart';
@@ -336,7 +336,7 @@
   }
 
   test_importLibrary_relative_beforeRelative() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'dart:async';
 
 import 'package:foo/foo.dart';
@@ -355,7 +355,7 @@
   }
 
   test_importLibrary_relative_beforeRelative_first() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'dart:async';
 
 import 'package:foo/foo.dart';
@@ -372,7 +372,7 @@
   }
 
   test_importLibrary_relative_last() async {
-    await _assertImportLibraries('''
+    await _assertImportLibrary('''
 import 'dart:async';
 
 import 'package:foo/foo.dart';
@@ -1955,18 +1955,15 @@
     expect(edit.replacement, equalsIgnoringWhitespace('implements A, B'));
   }
 
-  Future<Null> _assertImportLibraries(
+  Future<Null> _assertImportLibrary(
       String initialCode, List<String> newUris, String expectedCode) async {
     String path = provider.convertPath('/test.dart');
     addSource(path, initialCode);
     DartChangeBuilderImpl builder = new DartChangeBuilder(session);
     await builder.addFileEdit(path, (DartFileEditBuilder builder) {
-      Iterable<_MockSource> sources = newUris.map((newUri) {
-        String path =
-            newUri.contains(':') ? null : provider.convertPath('/$newUri');
-        return new _MockSource(path, Uri.parse(newUri));
-      });
-      builder.importLibraries(sources);
+      for (String newUri in newUris) {
+        builder.importLibrary(Uri.parse(newUri));
+      }
     });
 
     String resultCode = initialCode;
@@ -2168,16 +2165,3 @@
         unorderedEquals(['Object', 'A', 'B', 'C']));
   }
 }
-
-class _MockSource implements Source {
-  @override
-  final String fullName;
-
-  @override
-  final Uri uri;
-
-  _MockSource(this.fullName, this.uri);
-
-  @override
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}