Elements. Remove PrefixElementImpl.

For now, we have a not nice looking way to write / read Element(s). Most
of the elements are stored as their first fragment, and then asked for
elements. I start with PrefixElementImpl2 to stop doing this, and switch
to writing actual element reference. When we are done with all elements,
it will become nice again.

Change-Id: Ia18c2ab516ae06dc0da0b1ab022f217bf9a7400d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/431702
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 98699f9..ceefe75 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -110,7 +110,7 @@
 // TODO(scheglov): Clean up the list of implicitly analyzed files.
 class AnalysisDriver {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 460;
+  static const int DATA_VERSION = 461;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index b0e14de..1ee7229 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -8471,55 +8471,6 @@
   }
 }
 
-/// Currently we write [Element] using the first fragment.
-/// Usually this works (as good as a hack can), but [PrefixElementImpl2]
-/// does not have [FragmentImpl] fragments. So, we use this fake element.
-// TODO(scheglov): reconsider how we write Element2.
-// TODO(scheglov): remove this class
-class PrefixElementImpl extends FragmentImpl {
-  final PrefixElementImpl2 element2;
-
-  PrefixElementImpl(this.element2)
-    : super(
-        name: element2.name3 ?? '',
-        nameOffset: -1,
-        reference: element2.reference,
-      );
-
-  @override
-  List<Fragment> get children3 => throw UnimplementedError();
-
-  @override
-  Element get element => throw UnimplementedError();
-
-  @override
-  Fragment? get enclosingFragment => throw UnimplementedError();
-
-  @override
-  ElementKind get kind => ElementKind.PREFIX;
-
-  @override
-  Null get library => null;
-
-  @override
-  LibraryFragment? get libraryFragment => throw UnimplementedError();
-
-  @override
-  String? get name2 => throw UnimplementedError();
-
-  @override
-  int? get nameOffset2 => throw UnimplementedError();
-
-  @override
-  Fragment? get nextFragment => throw UnimplementedError();
-
-  @override
-  int get offset => throw UnimplementedError();
-
-  @override
-  Fragment? get previousFragment => throw UnimplementedError();
-}
-
 class PrefixElementImpl2 extends ElementImpl2 implements PrefixElement {
   @override
   final Reference reference;
@@ -8535,12 +8486,6 @@
   PrefixElementImpl2({required this.reference, required this.firstFragment})
     : lastFragment = firstFragment {
     reference.element2 = this;
-    asElement;
-  }
-
-  PrefixElementImpl get asElement {
-    return PrefixElementImpl(this);
-    // return imports.first.prefix!.element;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
index 2cda18e..9e96291 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
@@ -16,6 +16,9 @@
   withNothing,
 }
 
+// TODO(scheglov): remove once we untangle Element2 from Fragment in storage.
+enum ElementKind2 { importPrefix, other }
+
 enum ImportElementPrefixKind { isDeferred, isNotDeferred, isNull }
 
 class Tag {
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index c3e7d86..3599258 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -1962,18 +1962,25 @@
   }
 
   Element? readElement() {
-    var fragment = readFragmentOrMember();
-    switch (fragment) {
-      case null:
-        return null;
-      case PrefixElementImpl():
-        return fragment.element2;
-      case FragmentImpl():
-        return fragment.asElement2;
-      case ExecutableMember():
-        return fragment;
-      default:
-        throw UnimplementedError('${fragment.runtimeType}');
+    var kind = readEnum(ElementKind2.values);
+    switch (kind) {
+      case ElementKind2.importPrefix:
+        var referenceIndex = _reader.readUInt30();
+        var reference = _referenceReader.referenceOfIndex(referenceIndex);
+        return reference.element2 as PrefixElementImpl2;
+      case ElementKind2.other:
+        // TODO(scheglov): eventually stop using fragments here.
+        var fragment = readFragmentOrMember();
+        switch (fragment) {
+          case null:
+            return null;
+          case FragmentImpl():
+            return fragment.asElement2;
+          case ExecutableMember():
+            return fragment;
+          default:
+            throw UnimplementedError('${fragment.runtimeType}');
+        }
     }
   }
 
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 28c7cda..4667c9b 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -701,20 +701,30 @@
   // TODO(scheglov): Triage places where we write elements.
   // Some of then cannot be members, e.g. type names.
   void writeElement(Element? element) {
-    if (element case Member element) {
-      var baseElement = element.baseElement;
+    switch (element) {
+      case PrefixElementImpl2():
+        writeEnum(ElementKind2.importPrefix);
+        var reference = element.reference;
+        var referenceIndex = _references._indexOfReference(reference);
+        writeUInt30(referenceIndex);
+      default:
+        // TODO(scheglov): eventually stop using fragments here.
+        writeEnum(ElementKind2.other);
+        if (element case Member element) {
+          var baseElement = element.baseElement;
 
-      var typeArguments = _enclosingClassTypeArguments(
-        baseElement,
-        element.substitution.map,
-      );
+          var typeArguments = _enclosingClassTypeArguments(
+            baseElement,
+            element.substitution.map,
+          );
 
-      writeByte(Tag.MemberWithTypeArguments);
-      _writeElement(baseElement);
-      _writeTypeList(typeArguments);
-    } else {
-      writeByte(Tag.RawElement);
-      _writeElement(element);
+          writeByte(Tag.MemberWithTypeArguments);
+          _writeElement(baseElement);
+          _writeTypeList(typeArguments);
+        } else {
+          writeByte(Tag.RawElement);
+          _writeElement(element);
+        }
     }
   }
 
@@ -864,8 +874,6 @@
         _writeFragmentImpl(element.asElement);
       case NeverElementImpl2():
         _writeFragmentImpl(NeverFragmentImpl.instance);
-      case PrefixElementImpl2 element:
-        _writeFragmentImpl(element.asElement);
       case TopLevelVariableElementImpl2 element:
         _writeFragmentImpl(element.asElement);
       case TypeAliasElementImpl2 element: