Error reporting and ~no location data

We shouldn't crash and reporting something as being on line 1 of a file
because we don't know where in the file it is, doesn't seem right.

Change-Id: Ia8d6145e21a136903771d876633036b292ea12ac
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100842
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
diff --git a/pkg/front_end/lib/src/fasta/command_line_reporting.dart b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
index fbfd9df..15778043 100644
--- a/pkg/front_end/lib/src/fasta/command_line_reporting.dart
+++ b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
@@ -12,7 +12,7 @@
 
 import 'dart:typed_data' show Uint8List;
 
-import 'package:kernel/ast.dart' show Location;
+import 'package:kernel/ast.dart' show Location, TreeNode;
 
 import '../compute_platform_binaries_location.dart' show translateSdk;
 
@@ -77,6 +77,9 @@
       String path = relativizeUri(translateSdk(message.uri));
       int offset = message.charOffset;
       location ??= (offset == -1 ? null : getLocation(message.uri, offset));
+      if (location?.line == TreeNode.noOffset) {
+        location = null;
+      }
       String sourceLine = getSourceLine(location);
       if (sourceLine == null) {
         sourceLine = "";
@@ -110,7 +113,7 @@
         sourceLine = "\n$sourceLine\n$pointer";
       }
       String position =
-          location == null ? ":1" : ":${location.line}:${location.column}";
+          location == null ? "" : ":${location.line}:${location.column}";
       return "$path$position: $text$sourceLine";
     } else {
       return text;
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 8d2b369..07d9eb6 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -644,7 +644,7 @@
       // If [library] is null, we have already reported a problem that this
       // part is orphaned.
       List<LocatedMessage> context = <LocatedMessage>[
-        messagePartInPartLibraryContext.withLocation(library.fileUri, 0, 1),
+        messagePartInPartLibraryContext.withLocation(library.fileUri, -1, 1),
       ];
       for (int offset in partOffsets) {
         addProblem(messagePartInPart, offset, noLength, fileUri,
@@ -658,7 +658,7 @@
     parts.clear();
     if (exporters.isNotEmpty) {
       List<LocatedMessage> context = <LocatedMessage>[
-        messagePartExportContext.withLocation(fileUri, 0, 1),
+        messagePartExportContext.withLocation(fileUri, -1, 1),
       ];
       for (Export export in exporters) {
         export.exporter.addProblem(
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index f8709b7..5d366a5 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -6022,8 +6022,11 @@
   /// Return the text corresponding to [line] which is a 1-based line
   /// number. The returned line contains no line separators.
   String getTextLine(int line) {
+    if (source == null ||
+        source.isEmpty ||
+        lineStarts == null ||
+        lineStarts.isEmpty) return null;
     RangeError.checkValueInInterval(line, 1, lineStarts.length, 'line');
-    if (source == null || source.isEmpty) return null;
 
     cachedText ??= utf8.decode(source, allowMalformed: true);
     // -1 as line numbers start at 1.
@@ -6047,6 +6050,9 @@
 
   /// Translates an offset to line and column numbers in the given file.
   Location getLocation(Uri file, int offset) {
+    if (lineStarts == null || lineStarts.isEmpty) {
+      return new Location(file, TreeNode.noOffset, TreeNode.noOffset);
+    }
     RangeError.checkValueInInterval(offset, 0, lineStarts.last, 'offset');
     int low = 0, high = lineStarts.length - 1;
     while (low < high) {