Store lineStarts with units.

R=brianwilkerson@google.com

Change-Id: I570b172f6feae88c122536e4032860b7c9e01ebc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101077
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index c67f47a..cac4817 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -777,9 +777,7 @@
     // Read the unlinked bundle.
     _driverUnlinkedUnit = new AnalysisDriverUnlinkedUnit.fromBuffer(bytes);
     _unlinked2 = _driverUnlinkedUnit.unit2;
-    // TODO(scheglov) implement
-    _lineInfo = new LineInfo([0]);
-//    _lineInfo = new LineInfo(_unlinked.lineStarts);
+    _lineInfo = new LineInfo(_unlinked2.lineStarts);
 
     // Prepare API signature.
     var newApiSignature = new Uint8List.fromList(_unlinked2.apiSignature);
@@ -886,6 +884,7 @@
       imports: imports,
       parts: parts,
       isPartOf: isPartOf,
+      lineStarts: unit.lineInfo.lineStarts,
     );
   }
 
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 1b02655..c0551e8 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -20224,6 +20224,7 @@
     with _LinkedNodeUnitMixin
     implements idl.LinkedNodeUnit {
   bool _isSynthetic;
+  List<int> _lineStarts;
   LinkedNodeBuilder _node;
   UnlinkedTokensBuilder _tokens;
   String _uriStr;
@@ -20236,6 +20237,15 @@
   }
 
   @override
+  List<int> get lineStarts => _lineStarts ??= <int>[];
+
+  /// Offsets of the first character of each line in the source code.
+  set lineStarts(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._lineStarts = value;
+  }
+
+  @override
   LinkedNodeBuilder get node => _node;
 
   set node(LinkedNodeBuilder value) {
@@ -20258,16 +20268,19 @@
 
   LinkedNodeUnitBuilder(
       {bool isSynthetic,
+      List<int> lineStarts,
       LinkedNodeBuilder node,
       UnlinkedTokensBuilder tokens,
       String uriStr})
       : _isSynthetic = isSynthetic,
+        _lineStarts = lineStarts,
         _node = node,
         _tokens = tokens,
         _uriStr = uriStr;
 
   /// Flush [informative] data recursively.
   void flushInformative() {
+    _lineStarts = null;
     _node?.flushInformative();
     _tokens?.flushInformative();
   }
@@ -20283,9 +20296,13 @@
   }
 
   fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset offset_lineStarts;
     fb.Offset offset_node;
     fb.Offset offset_tokens;
     fb.Offset offset_uriStr;
+    if (!(_lineStarts == null || _lineStarts.isEmpty)) {
+      offset_lineStarts = fbBuilder.writeListUint32(_lineStarts);
+    }
     if (_node != null) {
       offset_node = _node.finish(fbBuilder);
     }
@@ -20299,6 +20316,9 @@
     if (_isSynthetic == true) {
       fbBuilder.addBool(3, true);
     }
+    if (offset_lineStarts != null) {
+      fbBuilder.addOffset(4, offset_lineStarts);
+    }
     if (offset_node != null) {
       fbBuilder.addOffset(2, offset_node);
     }
@@ -20329,6 +20349,7 @@
   _LinkedNodeUnitImpl(this._bc, this._bcOffset);
 
   bool _isSynthetic;
+  List<int> _lineStarts;
   idl.LinkedNode _node;
   idl.UnlinkedTokens _tokens;
   String _uriStr;
@@ -20340,6 +20361,13 @@
   }
 
   @override
+  List<int> get lineStarts {
+    _lineStarts ??=
+        const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 4, const <int>[]);
+    return _lineStarts;
+  }
+
+  @override
   idl.LinkedNode get node {
     _node ??= const _LinkedNodeReader().vTableGet(_bc, _bcOffset, 2, null);
     return _node;
@@ -20364,6 +20392,7 @@
   Map<String, Object> toJson() {
     Map<String, Object> _result = <String, Object>{};
     if (isSynthetic != false) _result["isSynthetic"] = isSynthetic;
+    if (lineStarts.isNotEmpty) _result["lineStarts"] = lineStarts;
     if (node != null) _result["node"] = node.toJson();
     if (tokens != null) _result["tokens"] = tokens.toJson();
     if (uriStr != '') _result["uriStr"] = uriStr;
@@ -20373,6 +20402,7 @@
   @override
   Map<String, Object> toMap() => {
         "isSynthetic": isSynthetic,
+        "lineStarts": lineStarts,
         "node": node,
         "tokens": tokens,
         "uriStr": uriStr,
@@ -29246,6 +29276,7 @@
   List<String> _exports;
   List<String> _imports;
   bool _isPartOf;
+  List<int> _lineStarts;
   List<String> _parts;
 
   @override
@@ -29283,6 +29314,15 @@
   }
 
   @override
+  List<int> get lineStarts => _lineStarts ??= <int>[];
+
+  /// Offsets of the first character of each line in the source code.
+  set lineStarts(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._lineStarts = value;
+  }
+
+  @override
   List<String> get parts => _parts ??= <String>[];
 
   /// URIs of `part` directives.
@@ -29295,15 +29335,19 @@
       List<String> exports,
       List<String> imports,
       bool isPartOf,
+      List<int> lineStarts,
       List<String> parts})
       : _apiSignature = apiSignature,
         _exports = exports,
         _imports = imports,
         _isPartOf = isPartOf,
+        _lineStarts = lineStarts,
         _parts = parts;
 
   /// Flush [informative] data recursively.
-  void flushInformative() {}
+  void flushInformative() {
+    _lineStarts = null;
+  }
 
   /// Accumulate non-[informative] data into [signature].
   void collectApiSignature(api_sig.ApiSignature signature) {
@@ -29351,6 +29395,7 @@
     fb.Offset offset_apiSignature;
     fb.Offset offset_exports;
     fb.Offset offset_imports;
+    fb.Offset offset_lineStarts;
     fb.Offset offset_parts;
     if (!(_apiSignature == null || _apiSignature.isEmpty)) {
       offset_apiSignature = fbBuilder.writeListUint32(_apiSignature);
@@ -29363,6 +29408,9 @@
       offset_imports = fbBuilder
           .writeList(_imports.map((b) => fbBuilder.writeString(b)).toList());
     }
+    if (!(_lineStarts == null || _lineStarts.isEmpty)) {
+      offset_lineStarts = fbBuilder.writeListUint32(_lineStarts);
+    }
     if (!(_parts == null || _parts.isEmpty)) {
       offset_parts = fbBuilder
           .writeList(_parts.map((b) => fbBuilder.writeString(b)).toList());
@@ -29380,6 +29428,9 @@
     if (_isPartOf == true) {
       fbBuilder.addBool(3, true);
     }
+    if (offset_lineStarts != null) {
+      fbBuilder.addOffset(5, offset_lineStarts);
+    }
     if (offset_parts != null) {
       fbBuilder.addOffset(4, offset_parts);
     }
@@ -29412,6 +29463,7 @@
   List<String> _exports;
   List<String> _imports;
   bool _isPartOf;
+  List<int> _lineStarts;
   List<String> _parts;
 
   @override
@@ -29442,6 +29494,13 @@
   }
 
   @override
+  List<int> get lineStarts {
+    _lineStarts ??=
+        const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 5, const <int>[]);
+    return _lineStarts;
+  }
+
+  @override
   List<String> get parts {
     _parts ??= const fb.ListReader<String>(const fb.StringReader())
         .vTableGet(_bc, _bcOffset, 4, const <String>[]);
@@ -29457,6 +29516,7 @@
     if (exports.isNotEmpty) _result["exports"] = exports;
     if (imports.isNotEmpty) _result["imports"] = imports;
     if (isPartOf != false) _result["isPartOf"] = isPartOf;
+    if (lineStarts.isNotEmpty) _result["lineStarts"] = lineStarts;
     if (parts.isNotEmpty) _result["parts"] = parts;
     return _result;
   }
@@ -29467,6 +29527,7 @@
         "exports": exports,
         "imports": imports,
         "isPartOf": isPartOf,
+        "lineStarts": lineStarts,
         "parts": parts,
       };
 
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 0a30d49..a14f872 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -2032,6 +2032,9 @@
 table LinkedNodeUnit {
   isSynthetic:bool (id: 3);
 
+  /// Offsets of the first character of each line in the source code.
+  lineStarts:[uint] (id: 4);
+
   node:LinkedNode (id: 2);
 
   tokens:UnlinkedTokens (id: 1);
@@ -3087,6 +3090,9 @@
   /// Is `true` if the unit contains a `part of` directive.
   isPartOf:bool (id: 3);
 
+  /// Offsets of the first character of each line in the source code.
+  lineStarts:[uint] (id: 5);
+
   /// URIs of `part` directives.
   parts:[string] (id: 4);
 }
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index d37f619..2916fa9 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -2670,6 +2670,11 @@
   @Id(3)
   bool get isSynthetic;
 
+  /// Offsets of the first character of each line in the source code.
+  @informative
+  @Id(4)
+  List<int> get lineStarts;
+
   @Id(2)
   LinkedNode get node;
 
@@ -4850,6 +4855,11 @@
   @Id(3)
   bool get isPartOf;
 
+  /// Offsets of the first character of each line in the source code.
+  @informative
+  @Id(5)
+  List<int> get lineStarts;
+
   /// URIs of `part` directives.
   @Id(4)
   List<String> get parts;
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index dce55d8..b3cd018 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -208,6 +208,7 @@
           LinkedNodeUnitBuilder(
             isSynthetic: unitContext.isSynthetic,
             uriStr: unitContext.uriStr,
+            lineStarts: unit.lineInfo.lineStarts,
             tokens: writer.tokensBuilder,
             node: unitLinkedNode,
           ),
diff --git a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
index 64cb319..f02b5e7 100644
--- a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
@@ -280,9 +280,10 @@
       var unitElement = CompilationUnitElementImpl.forLinkedNode(
         libraryElement,
         unitContext,
-        unitContainerRef.getChild(unitContext.uriStr),
+        unitContext.reference,
         unitNode,
       );
+      unitElement.lineInfo = unitNode.lineInfo;
       unitElement.source = unitSource;
       unitElement.librarySource = librarySource;
       units.add(unitElement);
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index f8a17c6..a1a58c1 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -6,6 +6,7 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -88,6 +89,7 @@
   CompilationUnit get unit_withDeclarations {
     if (_unit == null) {
       _unit = _astReader.readNode(data.node);
+      _unit.lineInfo = LineInfo(data.lineStarts);
     }
     return _unit;
   }