Improve input path handling and remove extra schemas.

Change-Id: I02a403284a2cc71cac908be4a7ec9f858cb5db47
Reviewed-on: https://dart-review.googlesource.com/c/89509
Auto-Submit: Peter von der Ahé <ahe@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Peter von der Ahé <ahe@google.com>
diff --git a/pkg/front_end/lib/src/fasta/colors.dart b/pkg/front_end/lib/src/fasta/colors.dart
index edde5bb..00ae3b6a 100644
--- a/pkg/front_end/lib/src/fasta/colors.dart
+++ b/pkg/front_end/lib/src/fasta/colors.dart
@@ -174,7 +174,7 @@
   }
 
   String numberOfColors = lines[0];
-  if (int.tryParse(numberOfColors) ?? -1 < 8) {
+  if ((int.tryParse(numberOfColors) ?? -1) < 8) {
     if (context.options.verbose) {
       print("Not enabling colors, less than 8 colors supported: "
           "${jsonEncode(numberOfColors)}.");
diff --git a/pkg/front_end/tool/_fasta/command_line.dart b/pkg/front_end/tool/_fasta/command_line.dart
index e4c2dff..f7c85f9 100644
--- a/pkg/front_end/tool/_fasta/command_line.dart
+++ b/pkg/front_end/tool/_fasta/command_line.dart
@@ -333,9 +333,7 @@
   final Uri singleRootBase = options["--single-root-base"];
 
   FileSystem fileSystem = StandardFileSystem.instance;
-  List<String> extraSchemes = const [];
   if (singleRootScheme != null) {
-    extraSchemes = [singleRootScheme];
     fileSystem = new SchemeBasedFileSystem({
       'file': fileSystem,
       'data': fileSystem,
@@ -367,8 +365,7 @@
     return new ProcessedOptions(
         options: new CompilerOptions()
           ..sdkSummary = options["--platform"]
-          ..librariesSpecificationUri =
-              resolveInputUri(arguments[1], extraSchemes: extraSchemes)
+          ..librariesSpecificationUri = resolveInputUri(arguments[1])
           ..setExitCodeOnProblem = true
           ..fileSystem = fileSystem
           ..packagesFileUri = packages
@@ -384,13 +381,12 @@
           ..bytecode = bytecode
           ..experimentalFlags = experimentalFlags,
         inputs: <Uri>[Uri.parse(arguments[0])],
-        output: resolveInputUri(arguments[3], extraSchemes: extraSchemes));
+        output: resolveInputUri(arguments[3]));
   } else if (arguments.isEmpty) {
     return throw new CommandLineProblem.deprecated("No Dart file specified.");
   }
 
-  final Uri defaultOutput =
-      resolveInputUri("${arguments.first}.dill", extraSchemes: extraSchemes);
+  final Uri defaultOutput = resolveInputUri("${arguments.first}.dill");
 
   final Uri output = options["-o"] ?? options["--output"] ?? defaultOutput;
 
@@ -424,7 +420,7 @@
   List<Uri> inputs = <Uri>[];
   if (areRestArgumentsInputs) {
     for (String argument in arguments) {
-      inputs.add(resolveInputUri(argument, extraSchemes: extraSchemes));
+      inputs.add(resolveInputUri(argument));
     }
   }
   return new ProcessedOptions(
diff --git a/pkg/front_end/tool/_fasta/resolve_input_uri.dart b/pkg/front_end/tool/_fasta/resolve_input_uri.dart
index f0b49d5..0dd3a17 100644
--- a/pkg/front_end/tool/_fasta/resolve_input_uri.dart
+++ b/pkg/front_end/tool/_fasta/resolve_input_uri.dart
@@ -2,18 +2,37 @@
 // 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.
 
-/// Resolve [string] as a [Uri].  If the input [string] starts with a supported
-/// scheme, it is resolved as a Uri of that scheme, otherwise the [string]
-/// is treated as a file system (possibly relative) path.
-///
-/// Three schemes are always supported by default: `dart`, `package`, and
-/// `data`. Additional supported schemes can be specified via [extraSchemes].
-Uri resolveInputUri(String string, {List<String> extraSchemes: const []}) {
-  if (string.startsWith('dart:')) return Uri.parse(string);
-  if (string.startsWith('data:')) return Uri.parse(string);
-  if (string.startsWith('package:')) return Uri.parse(string);
-  for (var scheme in extraSchemes) {
-    if (string.startsWith('$scheme:')) return Uri.parse(string);
+/// Detect if we're on Windows without importing `dart:io`.
+bool isWindows = new Uri.directory("C:\\").path ==
+    new Uri.directory("C:\\", windows: true).path;
+
+Uri resolveInputUri(String path) {
+  Uri uri;
+  if (path.indexOf(":") == -1) {
+    uri = new Uri.file(path, windows: isWindows);
+  } else if (!isWindows) {
+    uri = parseUri(path);
+  } else {
+    uri = resolveAmbiguousWindowsPath(path);
   }
-  return Uri.base.resolveUri(new Uri.file(string));
+  return Uri.base.resolveUri(uri);
+}
+
+Uri parseUri(String path) {
+  if (path.startsWith("file:")) {
+    if (Uri.base.scheme == "file") {
+      // The Uri class doesn't handle relative file URIs correctly, the
+      // following works around that issue.
+      return new Uri(path: Uri.parse("x-$path").path);
+    }
+  }
+  return Uri.parse(path);
+}
+
+Uri resolveAmbiguousWindowsPath(String path) {
+  try {
+    return new Uri.file(path, windows: isWindows);
+  } on ArgumentError catch (_) {
+    return parseUri(path);
+  }
 }
diff --git a/pkg/front_end/tool/_fasta/resolve_input_uri_test.dart b/pkg/front_end/tool/_fasta/resolve_input_uri_test.dart
index 0d66637..e520fec 100644
--- a/pkg/front_end/tool/_fasta/resolve_input_uri_test.dart
+++ b/pkg/front_end/tool/_fasta/resolve_input_uri_test.dart
@@ -2,40 +2,38 @@
 // 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:io' show Platform;
-
-import 'package:test/test.dart';
+import 'package:expect/expect.dart' show Expect;
 
 import 'resolve_input_uri.dart';
 
+test() {
+  // data URI scheme is supported by default'.
+  Expect.stringEquals('data', resolveInputUri('data:,foo').scheme);
+
+  // Custom Dart schemes are recognized by default.
+  Expect.stringEquals('dart', resolveInputUri('dart:foo').scheme);
+  Expect.stringEquals('package', resolveInputUri('package:foo').scheme);
+
+  // Unknown schemes are recognized by default.
+  Expect.stringEquals(
+      isWindows ? 'file' : 'c', resolveInputUri('c:/foo').scheme);
+  Expect.stringEquals('test', resolveInputUri('test:foo').scheme);
+  Expect.stringEquals(
+      'org-dartlang-foo', resolveInputUri('org-dartlang-foo:bar').scheme);
+  Expect.stringEquals('test', resolveInputUri('test:/foo').scheme);
+  Expect.stringEquals(
+      'org-dartlang-foo', resolveInputUri('org-dartlang-foo:/bar').scheme);
+  Expect.stringEquals(
+      "${Uri.base.resolve('file.txt')}", "${resolveInputUri('file:file.txt')}");
+}
+
 main() {
-  test('data URI scheme is supported by default', () {
-    expect(resolveInputUri('data:,foo').scheme, 'data');
-  });
-
-  test('internal dart schemes are recognized by default', () {
-    expect(resolveInputUri('dart:foo').scheme, 'dart');
-    expect(resolveInputUri('package:foo').scheme, 'package');
-  });
-
-  test('unknown schemes are not recognized by default', () {
-    expect(resolveInputUri('c:/foo').scheme, 'file');
-    if (Platform.isWindows) {
-      /// : is an invalid path character in windows.
-      expect(() => resolveInputUri('test:foo').scheme, throwsA(anything));
-      expect(() => resolveInputUri('org-dartlang-foo:bar').scheme,
-          throwsA(anything));
-    } else {
-      expect(resolveInputUri('test:foo').scheme, 'file');
-      expect(resolveInputUri('org-dartlang-foo:bar').scheme, 'file');
-    }
-  });
-
-  test('more schemes can be supported', () {
-    expect(resolveInputUri('test:foo', extraSchemes: ['test']).scheme, 'test');
-    expect(
-        resolveInputUri('org-dartlang-foo:bar',
-            extraSchemes: ['org-dartlang-foo']).scheme,
-        'org-dartlang-foo');
-  });
+  // Test platform default.
+  test();
+  // Test non-Windows behavior.
+  isWindows = false;
+  test();
+  // Test Windows behavior.
+  isWindows = true;
+  test();
 }