Augment. Support multiple augmentations of the same element in the same container.

The same mechanism is now also used to handle (not allowed) duplicate
declarations.

Change-Id: I814abcb15b7f2e7248701f754b7af1fdcb74f31a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/328900
Reviewed-by: Brian Wilkerson <brianwilkerson@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 c5f0765..5ae914a 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -88,7 +88,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 310;
+  static const int DATA_VERSION = 311;
 
   /// 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/display_string_builder.dart b/pkg/analyzer/lib/src/dart/element/display_string_builder.dart
index 787fce8..60d3e16 100644
--- a/pkg/analyzer/lib/src/dart/element/display_string_builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/display_string_builder.dart
@@ -299,6 +299,12 @@
   }
 
   void writeVariableElement(VariableElement element) {
+    switch (element) {
+      case FieldElement(isAugmentation: true):
+      case TopLevelVariableElement(isAugmentation: true):
+        _write('augment ');
+    }
+
     _writeType(element.type);
     _write(' ');
     _write(element.displayName);
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 7d321d9..3eb64fe 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -6375,6 +6375,19 @@
     setModifier(Modifier.SHOULD_USE_TYPE_FOR_INITIALIZER_INFERENCE, true);
   }
 
+  /// Return `true` if this variable needs the setter.
+  bool get hasSetter {
+    if (isConst) {
+      return false;
+    }
+
+    if (isLate) {
+      return !isFinal || !hasInitializer;
+    }
+
+    return !isFinal;
+  }
+
   @override
   bool get isConstantEvaluated => true;
 
@@ -6450,36 +6463,26 @@
     return _type!;
   }
 
-  /// Return `true` if this variable needs the setter.
-  bool get _hasSetter {
-    if (isConst) {
-      return false;
-    }
-
-    if (isLate) {
-      return !isFinal || !hasInitializer;
-    }
-
-    return !isFinal;
-  }
-
   void bindReference(Reference reference) {
     this.reference = reference;
     reference.element = this;
   }
 
-  void createImplicitAccessors(Reference enclosingRef, String name) {
-    getter = PropertyAccessorElementImpl_ImplicitGetter(
+  PropertyAccessorElementImpl createImplicitGetter(Reference reference) {
+    assert(getter == null);
+    return getter = PropertyAccessorElementImpl_ImplicitGetter(
       this,
-      reference: enclosingRef.getChild('@getter').getChild(name),
+      reference: reference,
     );
+  }
 
-    if (_hasSetter) {
-      setter = PropertyAccessorElementImpl_ImplicitSetter(
-        this,
-        reference: enclosingRef.getChild('@setter').getChild(name),
-      );
-    }
+  PropertyAccessorElementImpl createImplicitSetter(Reference reference) {
+    assert(hasSetter);
+    assert(setter == null);
+    return setter = PropertyAccessorElementImpl_ImplicitSetter(
+      this,
+      reference: reference,
+    );
   }
 
   void setLinkedData(Reference reference, ElementLinkedData linkedData) {
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 5c8d351..7149e86 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -717,7 +717,7 @@
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
 
     final reference = _readReference();
-    final name = reference.name;
+    final name = reference.elementName;
 
     var element = ClassElementImpl(name, -1);
 
@@ -790,7 +790,7 @@
     return _reader.readTypedList(() {
       var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
       final reference = _readReference();
-      final name = reference.name.ifEqualThen('new', '');
+      final name = reference.elementName.ifEqualThen('new', '');
       var element = ConstructorElementImpl(name, -1);
       var linkedData = ConstructorElementLinkedData(
         reference: reference,
@@ -895,7 +895,7 @@
   ) {
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
     final reference = _readReference();
-    final name = reference.name;
+    final name = reference.elementName;
 
     var element = EnumElementImpl(name, -1);
 
@@ -980,7 +980,7 @@
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
 
     final reference = _readReference();
-    final name = _reader.readBool() ? reference.name : null;
+    final name = _reader.readBool() ? reference.elementName : null;
 
     var element = ExtensionElementImpl(name, -1);
     element.setLinkedData(
@@ -1023,7 +1023,7 @@
   ) {
     final resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
     final reference = _readReference();
-    final name = reference.name;
+    final name = reference.elementName;
 
     final element = ExtensionTypeElementImpl(name, -1);
     element.setLinkedData(
@@ -1073,8 +1073,12 @@
     Reference classReference,
   ) {
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
+
     final reference = _readReference();
-    final name = reference.name;
+    final getterReference = _readOptionalReference();
+    final setterReference = _readOptionalReference();
+
+    final name = reference.elementName;
     var isConstElement = _reader.readBool();
 
     FieldElementImpl element;
@@ -1096,7 +1100,12 @@
     element.typeInferenceError = _readTopLevelInferenceError();
 
     if (!element.isAugmentation) {
-      element.createImplicitAccessors(classReference, name);
+      if (getterReference != null) {
+        element.createImplicitGetter(getterReference);
+      }
+      if (element.hasSetter && setterReference != null) {
+        element.createImplicitSetter(setterReference);
+      }
     }
 
     return element;
@@ -1136,7 +1145,7 @@
     unitElement.functions = _reader.readTypedList(() {
       var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
       final reference = _readReference();
-      final name = reference.name;
+      final name = reference.elementName;
 
       var element = FunctionElementImpl(name, -1);
 
@@ -1258,7 +1267,7 @@
     return _reader.readTypedList(() {
       var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
       final reference = _readReference();
-      final name = reference.name;
+      final name = reference.elementName;
       var element = MethodElementImpl(name, -1);
       var linkedData = MethodElementLinkedData(
         reference: reference,
@@ -1281,7 +1290,7 @@
   ) {
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
     final reference = _readReference();
-    final name = reference.name;
+    final name = reference.elementName;
 
     var element = MixinElementImpl(name, -1);
 
@@ -1335,18 +1344,24 @@
     }
   }
 
+  /// Read the reference of a non-local element.
+  Reference? _readOptionalReference() {
+    return _reader.readOptionalObject(
+      (reader) => _readReference(),
+    );
+  }
+
   /// TODO(scheglov) Deduplicate parameter reading implementation.
   List<ParameterElementImpl> _readParameters(
     ElementImpl enclosingElement,
     Reference enclosingReference,
   ) {
-    var containerRef = enclosingReference.getChild('@parameter');
     return _reader.readTypedList(() {
       var name = _reader.readStringReference();
       var isDefault = _reader.readBool();
       var isInitializingFormal = _reader.readBool();
       var isSuperFormal = _reader.readBool();
-      var reference = containerRef.getChild(name);
+      var reference = _readReference();
 
       var kindIndex = _reader.readByte();
       var kind = ResolutionReader._formalParameterKind(kindIndex);
@@ -1445,7 +1460,7 @@
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
 
     final reference = _readReference();
-    final name = reference.name;
+    final name = reference.elementName;
 
     var element = PropertyAccessorElementImpl(name, -1);
     PropertyAccessorElementFlags.read(_reader, element);
@@ -1557,8 +1572,12 @@
     Reference unitReference,
   ) {
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
+
     final reference = _readReference();
-    final name = reference.name;
+    final getterReference = _readOptionalReference();
+    final setterReference = _readOptionalReference();
+
+    final name = reference.elementName;
     var isConst = _reader.readBool();
 
     TopLevelVariableElementImpl element;
@@ -1579,7 +1598,13 @@
     element.isConst = isConst;
     TopLevelVariableElementFlags.read(_reader, element);
     element.typeInferenceError = _readTopLevelInferenceError();
-    element.createImplicitAccessors(unitReference, name);
+
+    if (getterReference != null) {
+      element.createImplicitGetter(getterReference);
+    }
+    if (element.hasSetter && setterReference != null) {
+      element.createImplicitSetter(setterReference);
+    }
 
     return element;
   }
@@ -1613,7 +1638,7 @@
   ) {
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
     final reference = _readReference();
-    final name = reference.name;
+    final name = reference.elementName;
 
     var isFunctionTypeAliasBased = _reader.readBool();
 
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 40f63fb..714b71a 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -378,6 +378,8 @@
   void _writeFieldElement(FieldElementImpl element) {
     _sink.writeUInt30(_resolutionSink.offset);
     _writeReference(element);
+    _writeOptionalReference(element.getter);
+    _writeOptionalReference(element.setter);
     _sink.writeBool(element is ConstFieldElementImpl);
     FieldElementFlags.write(_sink, element);
     _sink._writeTopLevelInferenceError(element.typeInferenceError);
@@ -559,6 +561,13 @@
     }
   }
 
+  /// Write the reference of a non-local element.
+  void _writeOptionalReference(ElementImpl? element) {
+    _sink.writeOptionalObject(element, (element) {
+      _writeReference(element);
+    });
+  }
+
   /// TODO(scheglov) Deduplicate parameter writing implementation.
   void _writeParameterElement(ParameterElement element) {
     element as ParameterElementImpl;
@@ -566,6 +575,7 @@
     _sink.writeBool(element is ConstVariableElement);
     _sink.writeBool(element.isInitializingFormal);
     _sink.writeBool(element.isSuperFormal);
+    _writeReference(element);
     _sink._writeFormalParameterKind(element);
     ParameterElementFlags.write(_sink, element);
 
@@ -623,6 +633,8 @@
   void _writeTopLevelVariableElement(TopLevelVariableElementImpl element) {
     _sink.writeUInt30(_resolutionSink.offset);
     _writeReference(element);
+    _writeOptionalReference(element.getter);
+    _writeOptionalReference(element.setter);
     _sink.writeBool(element.isConst);
     TopLevelVariableElementFlags.write(_sink, element);
     _sink._writeTopLevelInferenceError(element.typeInferenceError);
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 0aab366..a00f9e9 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -1173,23 +1173,23 @@
         element.hasImplicitType = true;
       }
 
-      element.createImplicitAccessors(enclosingRef, name);
+      {
+        final ref = enclosingRef.getChild('@getter').addChild(name);
+        final getter = element.createImplicitGetter(ref);
+        _enclosingContext.addPropertyAccessorSynthetic(getter);
+        _libraryBuilder.declare(name, ref);
+      }
+
+      if (element.hasSetter) {
+        final ref = enclosingRef.getChild('@setter').addChild(name);
+        final setter = element.createImplicitSetter(ref);
+        _enclosingContext.addPropertyAccessorSynthetic(setter);
+        _libraryBuilder.declare('$name=', ref);
+      }
 
       _linker.elementNodes[element] = variable;
       _enclosingContext.addTopLevelVariable(name, element);
       variable.declaredElement = element;
-
-      var getter = element.getter;
-      if (getter is PropertyAccessorElementImpl) {
-        _enclosingContext.addGetter(name, getter);
-        _libraryBuilder.declare(name, getter.reference!);
-      }
-
-      var setter = element.setter;
-      if (setter is PropertyAccessorElementImpl) {
-        _enclosingContext.addSetter(name, setter);
-        _libraryBuilder.declare('$name=', setter.reference!);
-      }
     }
 
     _buildType(node.variables.type);
@@ -1313,7 +1313,7 @@
       } else {
         final variable = property = TopLevelVariableElementImpl(name, -1)
           ..isSynthetic = true;
-        _enclosingContext.addTopLevelVariable(name, variable);
+        _enclosingContext.addTopLevelVariableSynthetic(reference, variable);
       }
     } else {
       final reference = enclosingRef.getChild('@field').getChild(name);
@@ -1324,7 +1324,7 @@
         final field = property = FieldElementImpl(name, -1)
           ..isStatic = accessorElement.isStatic
           ..isSynthetic = true;
-        _enclosingContext.addField(name, field);
+        _enclosingContext.addFieldSynthetic(reference, field);
       }
     }
 
@@ -1601,7 +1601,7 @@
     _classes.add(element);
     final containerName =
         element.isAugmentation ? '@classAugmentation' : '@class';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
   }
 
   Reference addConstructor(ConstructorElementImpl element) {
@@ -1610,21 +1610,21 @@
     final containerName =
         element.isAugmentation ? '@constructorAugmentation' : '@constructor';
     final referenceName = element.name.ifNotEmptyOrElse('new');
-    return _bindReference(containerName, referenceName, element);
+    return _addReference(containerName, referenceName, element);
   }
 
   Reference addEnum(String name, EnumElementImpl element) {
     _enums.add(element);
     final containerName =
         element.isAugmentation ? '@enumAugmentation' : '@enum';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
   }
 
   Reference addExtension(String name, ExtensionElementImpl element) {
     _extensions.add(element);
     final containerName =
         element.isAugmentation ? '@extensionAugmentation' : '@extension';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
   }
 
   Reference addExtensionType(String name, ExtensionTypeElementImpl element) {
@@ -1632,42 +1632,47 @@
     final containerName = element.isAugmentation
         ? '@extensionTypeAugmentation'
         : '@extensionType';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
   }
 
   Reference addField(String name, FieldElementImpl element) {
     _fields.add(element);
     final containerName =
         element.isAugmentation ? '@fieldAugmentation' : '@field';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
+  }
+
+  void addFieldSynthetic(Reference reference, FieldElementImpl element) {
+    _fields.add(element);
+    _bindReference(reference, element);
   }
 
   Reference addFunction(String name, FunctionElementImpl element) {
     _functions.add(element);
     final containerName =
         element.isAugmentation ? '@functionAugmentation' : '@function';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
   }
 
   Reference addGetter(String name, PropertyAccessorElementImpl element) {
     _propertyAccessors.add(element);
     final containerName =
         element.isAugmentation ? '@getterAugmentation' : '@getter';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
   }
 
   Reference addMethod(String name, MethodElementImpl element) {
     _methods.add(element);
     final containerName =
         element.isAugmentation ? '@methodAugmentation' : '@method';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
   }
 
   Reference addMixin(String name, MixinElementImpl element) {
     _mixins.add(element);
     final containerName =
         element.isAugmentation ? '@mixinAugmentation' : '@mixin';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
   }
 
   void addNonSyntheticField(FieldElementImpl element) {
@@ -1680,16 +1685,16 @@
       return;
     }
 
-    element.createImplicitAccessors(reference, name);
-
-    var getter = element.getter;
-    if (getter is PropertyAccessorElementImpl) {
-      addGetter(name, getter);
+    {
+      final getterRef = reference.getChild('@getter').addChild(name);
+      final getter = element.createImplicitGetter(getterRef);
+      _propertyAccessors.add(getter);
     }
 
-    var setter = element.setter;
-    if (setter is PropertyAccessorElementImpl) {
-      addSetter(name, setter);
+    if (element.hasSetter) {
+      final setterRef = reference.getChild('@setter').addChild(name);
+      final setter = element.createImplicitSetter(setterRef);
+      _propertyAccessors.add(setter);
     }
   }
 
@@ -1698,15 +1703,19 @@
     if (name == null) {
       return null;
     } else {
-      return _bindReference('@parameter', name, element);
+      return _addReference('@parameter', name, element);
     }
   }
 
+  void addPropertyAccessorSynthetic(PropertyAccessorElementImpl element) {
+    _propertyAccessors.add(element);
+  }
+
   Reference addSetter(String name, PropertyAccessorElementImpl element) {
     _propertyAccessors.add(element);
     final containerName =
         element.isAugmentation ? '@setterAugmentation' : '@setter';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
   }
 
   Reference addTopLevelVariable(
@@ -1714,12 +1723,18 @@
     _topLevelVariables.add(element);
     final containerName =
         element.isAugmentation ? '@variableAugmentation' : '@variable';
-    return _bindReference(containerName, name, element);
+    return _addReference(containerName, name, element);
+  }
+
+  void addTopLevelVariableSynthetic(
+      Reference reference, TopLevelVariableElementImpl element) {
+    _topLevelVariables.add(element);
+    _bindReference(reference, element);
   }
 
   Reference addTypeAlias(String name, TypeAliasElementImpl element) {
     _typeAliases.add(element);
-    return _bindReference('@typeAlias', name, element);
+    return _addReference('@typeAlias', name, element);
   }
 
   void addTypeParameter(String name, TypeParameterElementImpl element) {
@@ -1727,16 +1742,20 @@
     this.element.encloseElement(element);
   }
 
-  Reference _bindReference(
+  Reference _addReference(
     String containerName,
     String name,
     ElementImpl element,
   ) {
     var containerRef = this.reference.getChild(containerName);
-    var reference = containerRef.getChild(name);
+    var reference = containerRef.addChild(name);
+    _bindReference(reference, element);
+    return reference;
+  }
+
+  void _bindReference(Reference reference, ElementImpl element) {
     reference.element = element;
     element.reference = reference;
     this.element.encloseElement(element);
-    return reference;
   }
 }
diff --git a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
index c4079ba..c717813 100644
--- a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
@@ -194,8 +194,16 @@
       return createLibraryElementForReading(uri);
     }
 
-    var parent = reference.parent!.parent!;
-    var parentElement = elementOfReference(parent);
+    // Should be `@method`, `@constructor`, etc.
+    // If a duplicates container, skip it up.
+    var containerInClass = reference.parent!;
+    if (containerInClass.name == '@def') {
+      containerInClass = containerInClass.parent!.parent!;
+    }
+
+    // Only classes delay creating children.
+    final classRef = containerInClass.parent!;
+    final parentElement = elementOfReference(classRef);
 
     if (parentElement is InstanceElementImpl) {
       parentElement.linkedData?.readMembers(parentElement);
diff --git a/pkg/analyzer/lib/src/summary2/reference.dart b/pkg/analyzer/lib/src/summary2/reference.dart
index ffb4ac7..5e05c60 100644
--- a/pkg/analyzer/lib/src/summary2/reference.dart
+++ b/pkg/analyzer/lib/src/summary2/reference.dart
@@ -26,10 +26,10 @@
 /// There is only one reference object per [Element].
 class Reference {
   /// The parent of this reference, or `null` if the root.
-  final Reference? parent;
+  Reference? parent;
 
   /// The simple name of the reference in its [parent].
-  final String name;
+  String name;
 
   /// The corresponding [Element], or `null` if a named container.
   Element? element;
@@ -54,6 +54,19 @@
   @visibleForTesting
   Object? get childrenUnionForTesting => _childrenUnion;
 
+  /// The name of the element that this reference represents.
+  ///
+  /// Normally, this is [name]. But in case of duplicate declarations, such
+  /// as augmentations (which is allowed by the specification), or invalid
+  /// code, the actual name is the name of the parent of the duplicates
+  /// container `@def`.
+  String get elementName {
+    if (parent?.name == '@def') {
+      return parent!.parent!.name;
+    }
+    return name;
+  }
+
   bool get isLibrary => parent?.isRoot == true;
 
   bool get isPrefix => parent?.name == '@prefix';
@@ -75,6 +88,38 @@
     return (childrenUnion as Map<String, Reference>)[name];
   }
 
+  /// Adds a new child with the given [name].
+  ///
+  /// This method should be used when a new declaration of an element with
+  /// this name is processed. If there is no existing child with this name,
+  /// this method works exactly as [getChild]. If there is a duplicate, which
+  /// should happen rarely, an intermediate `@def` container is added, the
+  /// existing child is transferred to it and renamed to `0`, then a new child
+  /// is added with name `1`. Additional duplicate children get names `2`, etc.
+  Reference addChild(String name) {
+    final existing = this[name];
+
+    // If not a duplicate.
+    if (existing == null) {
+      return getChild(name);
+    }
+
+    var def = existing['@def'];
+
+    // If no duplicates container yet.
+    if (def == null) {
+      removeChild(name); // existing
+      def = getChild(name).getChild('@def');
+      def._addChild('0', existing);
+      existing.parent = def;
+      existing.name = '0';
+    }
+
+    // Add a new child to the duplicates container.
+    final indexStr = '${def.children.length}';
+    return def.getChild(indexStr);
+  }
+
   /// Return the child with the given name, create if does not exist yet.
   Reference getChild(String name) {
     name = _rewriteDartUi(name);
@@ -121,6 +166,25 @@
   @override
   String toString() => parent == null ? 'root' : '$parent::$name';
 
+  void _addChild(String name, Reference child) {
+    name = _rewriteDartUi(name);
+
+    final childrenUnion = _childrenUnion;
+    if (childrenUnion == null) {
+      // 0 -> 1 children.
+      _childrenUnion = child;
+      return;
+    }
+    if (childrenUnion is Reference) {
+      // 1 -> 2 children.
+      final childrenUnionAsMap = _childrenUnion = <String, Reference>{};
+      childrenUnionAsMap[childrenUnion.name] = childrenUnion;
+      childrenUnionAsMap[name] = child;
+      return;
+    }
+    (childrenUnion as Map<String, Reference>)[name] ??= child;
+  }
+
   /// TODO(scheglov) Remove it, once when the actual issue is fixed.
   /// https://buganizer.corp.google.com/issues/203423390
   static String _rewriteDartUi(String name) {
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index f0d02c3..71a5e6c 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -296,13 +296,6 @@
     var reference = e.reference;
     if (reference == null) {
       fail('Every constructor must have a reference.');
-    } else {
-      var classReference = reference.parent!.parent!;
-      // We need this `if` for duplicate declarations.
-      // The reference might be filled by another declaration.
-      if (identical(classReference.element, e.enclosingElement)) {
-        expect(reference.element, same(e));
-      }
     }
 
     _sink.writeIndentedLine(() {
@@ -316,6 +309,7 @@
     });
 
     _sink.withIndent(() {
+      _writeReference(e);
       _writeDocumentation(e);
       _writeMetadata(e);
       _writeSinceSdkVersion(e);
@@ -712,7 +706,7 @@
     }
   }
 
-  void _writeMethodElement(MethodElement e) {
+  void _writeMethodElement(MethodElementImpl e) {
     _sink.writeIndentedLine(() {
       _sink.writeIf(e.isAugmentation, 'augment ');
       _sink.writeIf(e.isSynthetic, 'synthetic ');
@@ -725,6 +719,7 @@
     });
 
     _sink.withIndent(() {
+      _writeReference(e);
       _writeDocumentation(e);
       _writeMetadata(e);
       _writeSinceSdkVersion(e);
@@ -757,7 +752,7 @@
     }
   }
 
-  void _writeMethods(List<MethodElement> elements) {
+  void _writeMethods(List<MethodElementImpl> elements) {
     _writeElements('methods', elements, _writeMethodElement);
   }
 
@@ -809,6 +804,8 @@
   }
 
   void _writeParameterElement(ParameterElement e) {
+    e as ParameterElementImpl;
+
     _sink.writeIndentedLine(() {
       if (e.isRequiredPositional) {
         _sink.write('requiredPositional ');
@@ -838,6 +835,7 @@
     });
 
     _sink.withIndent(() {
+      _writeReference(e);
       _writeType('type', e.type);
       _writeMetadata(e);
       _writeSinceSdkVersion(e);
diff --git a/pkg/analyzer/test/src/summary/elements_test.dart b/pkg/analyzer/test/src/summary/elements_test.dart
index 16c380b..a75b7ed 100644
--- a/pkg/analyzer/test/src/summary/elements_test.dart
+++ b/pkg/analyzer/test/src/summary/elements_test.dart
@@ -77,8 +77,10 @@
             augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
             constructors
               synthetic @-1
+                reference: self::@augmentation::package:test/a.dart::@class::A::@constructor::new
             methods
               foo @47
+                reference: self::@augmentation::package:test/a.dart::@class::A::@method::foo
                 returnType: void
             augmented
               constructors
@@ -91,6 +93,7 @@
             augmentationTarget: self::@augmentation::package:test/a.dart::@class::A
             methods
               bar @84
+                reference: self::@augmentation::package:test/a.dart::@classAugmentation::A::@method::bar
                 returnType: void
 ''');
   }
@@ -1625,7 +1628,80 @@
 ''');
   }
 
-  test_augmented_getters_augment_getter2() async {
+  test_augmented_getters_augment_getter2_oneLib_oneTop() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+library augment 'test.dart';
+augment class A {
+  augment int get foo => 0;
+  augment int get foo => 0;
+}
+''');
+
+    var library = await buildLibrary(r'''
+import augment 'a.dart';
+class A {
+  int get foo => 0;
+}
+''');
+
+    configuration
+      ..withReferences = true
+      ..withPropertyLinking = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @31
+        reference: self::@class::A
+        augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
+        fields
+          synthetic foo @-1
+            reference: self::@class::A::@field::foo
+            type: int
+            id: field_0
+            getter: getter_0
+        constructors
+          synthetic @-1
+            reference: self::@class::A::@constructor::new
+        accessors
+          get foo @45
+            reference: self::@class::A::@getter::foo
+            returnType: int
+            id: getter_0
+            variable: field_0
+            augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A::@getterAugmentation::foo::@def::0
+        augmented
+          fields
+            self::@class::A::@field::foo
+          constructors
+            self::@class::A::@constructor::new
+          accessors
+            self::@augmentation::package:test/a.dart::@classAugmentation::A::@getterAugmentation::foo::@def::1
+  augmentationImports
+    package:test/a.dart
+      definingUnit
+        classes
+          augment class A @43
+            reference: self::@augmentation::package:test/a.dart::@classAugmentation::A
+            augmentationTarget: self::@class::A
+            accessors
+              augment get foo @65
+                reference: self::@augmentation::package:test/a.dart::@classAugmentation::A::@getterAugmentation::foo::@def::0
+                returnType: int
+                id: getter_1
+                variable: field_0
+                augmentationTarget: self::@class::A::@getter::foo
+                augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A::@getterAugmentation::foo::@def::1
+              augment get foo @93
+                reference: self::@augmentation::package:test/a.dart::@classAugmentation::A::@getterAugmentation::foo::@def::1
+                returnType: int
+                id: getter_2
+                variable: field_0
+                augmentationTarget: self::@augmentation::package:test/a.dart::@classAugmentation::A::@getterAugmentation::foo::@def::0
+''');
+  }
+
+  test_augmented_getters_augment_getter2_twoLib() async {
     newFile('$testPackageLibPath/a.dart', r'''
 library augment 'test.dart';
 augment class A {
@@ -2019,7 +2095,128 @@
 ''');
   }
 
-  test_augmented_methods_augment2() async {
+  test_augmented_methods_augment2_oneLib_oneTop() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+library augment 'test.dart';
+augment class A {
+  augment void foo() {}
+  augment void foo() {}
+}
+''');
+
+    var library = await buildLibrary(r'''
+import augment 'a.dart';
+class A {
+  void foo() {}
+}
+''');
+
+    configuration.withReferences = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @31
+        reference: self::@class::A
+        augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
+        constructors
+          synthetic @-1
+            reference: self::@class::A::@constructor::new
+        methods
+          foo @42
+            reference: self::@class::A::@method::foo
+            returnType: void
+            augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A::@methodAugmentation::foo::@def::0
+        augmented
+          constructors
+            self::@class::A::@constructor::new
+          methods
+            self::@augmentation::package:test/a.dart::@classAugmentation::A::@methodAugmentation::foo::@def::1
+  augmentationImports
+    package:test/a.dart
+      definingUnit
+        classes
+          augment class A @43
+            reference: self::@augmentation::package:test/a.dart::@classAugmentation::A
+            augmentationTarget: self::@class::A
+            methods
+              augment foo @62
+                reference: self::@augmentation::package:test/a.dart::@classAugmentation::A::@methodAugmentation::foo::@def::0
+                returnType: void
+                augmentationTarget: self::@class::A::@method::foo
+                augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A::@methodAugmentation::foo::@def::1
+              augment foo @86
+                reference: self::@augmentation::package:test/a.dart::@classAugmentation::A::@methodAugmentation::foo::@def::1
+                returnType: void
+                augmentationTarget: self::@augmentation::package:test/a.dart::@classAugmentation::A::@methodAugmentation::foo::@def::0
+''');
+  }
+
+  test_augmented_methods_augment2_oneLib_twoTop() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+library augment 'test.dart';
+augment class A {
+  augment void foo() {}
+}
+augment class A {
+  augment void foo() {}
+}
+''');
+
+    var library = await buildLibrary(r'''
+import augment 'a.dart';
+class A {
+  void foo() {}
+}
+''');
+
+    configuration.withReferences = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @31
+        reference: self::@class::A
+        augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::0
+        constructors
+          synthetic @-1
+            reference: self::@class::A::@constructor::new
+        methods
+          foo @42
+            reference: self::@class::A::@method::foo
+            returnType: void
+            augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::0::@methodAugmentation::foo
+        augmented
+          constructors
+            self::@class::A::@constructor::new
+          methods
+            self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::1::@methodAugmentation::foo
+  augmentationImports
+    package:test/a.dart
+      definingUnit
+        classes
+          augment class A @43
+            reference: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::0
+            augmentationTarget: self::@class::A
+            augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::1
+            methods
+              augment foo @62
+                reference: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::0::@methodAugmentation::foo
+                returnType: void
+                augmentationTarget: self::@class::A::@method::foo
+                augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::1::@methodAugmentation::foo
+          augment class A @87
+            reference: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::1
+            augmentationTarget: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::0
+            methods
+              augment foo @106
+                reference: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::1::@methodAugmentation::foo
+                returnType: void
+                augmentationTarget: self::@augmentation::package:test/a.dart::@classAugmentation::A::@def::0::@methodAugmentation::foo
+''');
+  }
+
+  test_augmented_methods_augment2_twoLib() async {
     newFile('$testPackageLibPath/a.dart', r'''
 library augment 'test.dart';
 import augment 'b.dart';
@@ -4346,33 +4543,42 @@
   test_class_constructor_field_formal_multiple_matching_fields() async {
     // This is a compile-time error but it should still analyze consistently.
     var library = await buildLibrary('class C { C(this.x); int x; String x; }');
+    configuration.withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
     classes
       class C @6
+        reference: self::@class::C
         fields
           x @25
+            reference: self::@class::C::@field::x::@def::0
             type: int
           x @35
+            reference: self::@class::C::@field::x::@def::1
             type: String
         constructors
           @10
+            reference: self::@class::C::@constructor::new
             parameters
               requiredPositional final this.x @17
                 type: int
-                field: self::@class::C::@field::x
+                field: self::@class::C::@field::x::@def::0
         accessors
           synthetic get x @-1
+            reference: self::@class::C::@getter::x::@def::0
             returnType: int
           synthetic set x= @-1
+            reference: self::@class::C::@setter::x::@def::0
             parameters
               requiredPositional _x @-1
                 type: int
             returnType: void
           synthetic get x @-1
+            reference: self::@class::C::@getter::x::@def::1
             returnType: String
           synthetic set x= @-1
+            reference: self::@class::C::@setter::x::@def::1
             parameters
               requiredPositional _x @-1
                 type: String
@@ -23169,50 +23375,231 @@
 
   test_duplicateDeclaration_class() async {
     var library = await buildLibrary(r'''
-class A {}
 class A {
-  var x;
+  static const f01 = 0;
+  static const f02 = f01;
 }
+
 class A {
-  var y = 0;
+  static const f11 = 0;
+  static const f12 = f11;
+}
+
+class A {
+  static const f21 = 0;
+  static const f22 = f21;
 }
 ''');
+    configuration.withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
     classes
       class A @6
-        constructors
-          synthetic @-1
-      class A @17
+        reference: self::@class::A::@def::0
         fields
-          x @27
-            type: dynamic
-        constructors
-          synthetic @-1
-        accessors
-          synthetic get x @-1
-            returnType: dynamic
-          synthetic set x= @-1
-            parameters
-              requiredPositional _x @-1
-                type: dynamic
-            returnType: void
-      class A @38
-        fields
-          y @48
+          static const f01 @25
+            reference: self::@class::A::@def::0::@field::f01
             type: int
             shouldUseTypeForInitializerInference: false
+            constantInitializer
+              IntegerLiteral
+                literal: 0 @31
+                staticType: int
+          static const f02 @49
+            reference: self::@class::A::@def::0::@field::f02
+            type: int
+            shouldUseTypeForInitializerInference: false
+            constantInitializer
+              SimpleIdentifier
+                token: f01 @55
+                staticElement: self::@class::A::@def::0::@getter::f01
+                staticType: int
         constructors
           synthetic @-1
+            reference: self::@class::A::@def::0::@constructor::new
         accessors
-          synthetic get y @-1
+          synthetic static get f01 @-1
+            reference: self::@class::A::@def::0::@getter::f01
             returnType: int
-          synthetic set y= @-1
+          synthetic static get f02 @-1
+            reference: self::@class::A::@def::0::@getter::f02
+            returnType: int
+      class A @69
+        reference: self::@class::A::@def::1
+        fields
+          static const f11 @88
+            reference: self::@class::A::@def::1::@field::f11
+            type: int
+            shouldUseTypeForInitializerInference: false
+            constantInitializer
+              IntegerLiteral
+                literal: 0 @94
+                staticType: int
+          static const f12 @112
+            reference: self::@class::A::@def::1::@field::f12
+            type: int
+            shouldUseTypeForInitializerInference: false
+            constantInitializer
+              SimpleIdentifier
+                token: f11 @118
+                staticElement: self::@class::A::@def::1::@getter::f11
+                staticType: int
+        constructors
+          synthetic @-1
+            reference: self::@class::A::@def::1::@constructor::new
+        accessors
+          synthetic static get f11 @-1
+            reference: self::@class::A::@def::1::@getter::f11
+            returnType: int
+          synthetic static get f12 @-1
+            reference: self::@class::A::@def::1::@getter::f12
+            returnType: int
+      class A @132
+        reference: self::@class::A::@def::2
+        fields
+          static const f21 @151
+            reference: self::@class::A::@def::2::@field::f21
+            type: int
+            shouldUseTypeForInitializerInference: false
+            constantInitializer
+              IntegerLiteral
+                literal: 0 @157
+                staticType: int
+          static const f22 @175
+            reference: self::@class::A::@def::2::@field::f22
+            type: int
+            shouldUseTypeForInitializerInference: false
+            constantInitializer
+              SimpleIdentifier
+                token: f21 @181
+                staticElement: self::@class::A::@def::2::@getter::f21
+                staticType: int
+        constructors
+          synthetic @-1
+            reference: self::@class::A::@def::2::@constructor::new
+        accessors
+          synthetic static get f21 @-1
+            reference: self::@class::A::@def::2::@getter::f21
+            returnType: int
+          synthetic static get f22 @-1
+            reference: self::@class::A::@def::2::@getter::f22
+            returnType: int
+''');
+  }
+
+  test_duplicateDeclaration_class_constructor_unnamed() async {
+    var library = await buildLibrary(r'''
+class A {
+  A.named();
+  A.named();
+}
+''');
+    configuration.withReferences = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        reference: self::@class::A
+        constructors
+          named @14
+            reference: self::@class::A::@constructor::named::@def::0
+            periodOffset: 13
+            nameEnd: 19
+          named @27
+            reference: self::@class::A::@constructor::named::@def::1
+            periodOffset: 26
+            nameEnd: 32
+''');
+  }
+
+  test_duplicateDeclaration_class_field() async {
+    var library = await buildLibrary(r'''
+class A {
+  int foo;
+  double foo;
+}
+''');
+    configuration
+      ..withPropertyLinking = true
+      ..withReferences = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        reference: self::@class::A
+        fields
+          foo @16
+            reference: self::@class::A::@field::foo::@def::0
+            type: int
+            id: field_0
+            getter: getter_0
+            setter: setter_0
+          foo @30
+            reference: self::@class::A::@field::foo::@def::1
+            type: double
+            id: field_1
+            getter: getter_1
+            setter: setter_1
+        constructors
+          synthetic @-1
+            reference: self::@class::A::@constructor::new
+        accessors
+          synthetic get foo @-1
+            reference: self::@class::A::@getter::foo::@def::0
+            returnType: int
+            id: getter_0
+            variable: field_0
+          synthetic set foo= @-1
+            reference: self::@class::A::@setter::foo::@def::0
             parameters
-              requiredPositional _y @-1
+              requiredPositional _foo @-1
                 type: int
             returnType: void
+            id: setter_0
+            variable: field_0
+          synthetic get foo @-1
+            reference: self::@class::A::@getter::foo::@def::1
+            returnType: double
+            id: getter_1
+            variable: field_1
+          synthetic set foo= @-1
+            reference: self::@class::A::@setter::foo::@def::1
+            parameters
+              requiredPositional _foo @-1
+                type: double
+            returnType: void
+            id: setter_1
+            variable: field_1
+''');
+  }
+
+  test_duplicateDeclaration_class_method() async {
+    var library = await buildLibrary(r'''
+class A {
+  void foo() {}
+  void foo() {}
+}
+''');
+    configuration.withReferences = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        reference: self::@class::A
+        constructors
+          synthetic @-1
+            reference: self::@class::A::@constructor::new
+        methods
+          foo @17
+            reference: self::@class::A::@method::foo::@def::0
+            returnType: void
+          foo @33
+            reference: self::@class::A::@method::foo::@def::1
+            returnType: void
 ''');
   }
 
@@ -23274,14 +23661,17 @@
 enum E {a, b}
 enum E {c, d, e}
 ''');
+    configuration.withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
     enums
       enum E @5
+        reference: self::@enum::E::@def::0
         supertype: Enum
         fields
           static const enumConstant a @8
+            reference: self::@enum::E::@def::0::@field::a
             type: E
             shouldUseTypeForInitializerInference: false
             constantInitializer
@@ -23289,14 +23679,15 @@
                 constructorName: ConstructorName
                   type: NamedType
                     name: E @-1
-                    element: self::@enum::E
+                    element: self::@enum::E::@def::0
                     type: E
-                  staticElement: self::@enum::E::@constructor::new
+                  staticElement: self::@enum::E::@def::0::@constructor::new
                 argumentList: ArgumentList
                   leftParenthesis: ( @0
                   rightParenthesis: ) @0
                 staticType: E
           static const enumConstant b @11
+            reference: self::@enum::E::@def::0::@field::b
             type: E
             shouldUseTypeForInitializerInference: false
             constantInitializer
@@ -23304,14 +23695,15 @@
                 constructorName: ConstructorName
                   type: NamedType
                     name: E @-1
-                    element: self::@enum::E
+                    element: self::@enum::E::@def::0
                     type: E
-                  staticElement: self::@enum::E::@constructor::new
+                  staticElement: self::@enum::E::@def::0::@constructor::new
                 argumentList: ArgumentList
                   leftParenthesis: ( @0
                   rightParenthesis: ) @0
                 staticType: E
           synthetic static const values @-1
+            reference: self::@enum::E::@def::0::@field::values
             type: List<E>
             constantInitializer
               ListLiteral
@@ -23319,27 +23711,33 @@
                 elements
                   SimpleIdentifier
                     token: a @-1
-                    staticElement: self::@enum::E::@getter::a
+                    staticElement: self::@enum::E::@def::0::@getter::a
                     staticType: E
                   SimpleIdentifier
                     token: b @-1
-                    staticElement: self::@enum::E::@getter::b
+                    staticElement: self::@enum::E::@def::0::@getter::b
                     staticType: E
                 rightBracket: ] @0
                 staticType: List<E>
         constructors
           synthetic const @-1
+            reference: self::@enum::E::@def::0::@constructor::new
         accessors
           synthetic static get a @-1
+            reference: self::@enum::E::@def::0::@getter::a
             returnType: E
           synthetic static get b @-1
+            reference: self::@enum::E::@def::0::@getter::b
             returnType: E
           synthetic static get values @-1
+            reference: self::@enum::E::@def::0::@getter::values
             returnType: List<E>
       enum E @19
+        reference: self::@enum::E::@def::1
         supertype: Enum
         fields
           static const enumConstant c @22
+            reference: self::@enum::E::@def::1::@field::c
             type: E
             shouldUseTypeForInitializerInference: false
             constantInitializer
@@ -23347,14 +23745,15 @@
                 constructorName: ConstructorName
                   type: NamedType
                     name: E @-1
-                    element: self::@enum::E
+                    element: self::@enum::E::@def::0
                     type: E
-                  staticElement: self::@enum::E::@constructor::new
+                  staticElement: self::@enum::E::@def::0::@constructor::new
                 argumentList: ArgumentList
                   leftParenthesis: ( @0
                   rightParenthesis: ) @0
                 staticType: E
           static const enumConstant d @25
+            reference: self::@enum::E::@def::1::@field::d
             type: E
             shouldUseTypeForInitializerInference: false
             constantInitializer
@@ -23362,14 +23761,15 @@
                 constructorName: ConstructorName
                   type: NamedType
                     name: E @-1
-                    element: self::@enum::E
+                    element: self::@enum::E::@def::0
                     type: E
-                  staticElement: self::@enum::E::@constructor::new
+                  staticElement: self::@enum::E::@def::0::@constructor::new
                 argumentList: ArgumentList
                   leftParenthesis: ( @0
                   rightParenthesis: ) @0
                 staticType: E
           static const enumConstant e @28
+            reference: self::@enum::E::@def::1::@field::e
             type: E
             shouldUseTypeForInitializerInference: false
             constantInitializer
@@ -23377,14 +23777,15 @@
                 constructorName: ConstructorName
                   type: NamedType
                     name: E @-1
-                    element: self::@enum::E
+                    element: self::@enum::E::@def::0
                     type: E
-                  staticElement: self::@enum::E::@constructor::new
+                  staticElement: self::@enum::E::@def::0::@constructor::new
                 argumentList: ArgumentList
                   leftParenthesis: ( @0
                   rightParenthesis: ) @0
                 staticType: E
           synthetic static const values @-1
+            reference: self::@enum::E::@def::1::@field::values
             type: List<E>
             constantInitializer
               ListLiteral
@@ -23392,76 +23793,86 @@
                 elements
                   SimpleIdentifier
                     token: c @-1
-                    staticElement: self::@enum::E::@getter::c
+                    staticElement: self::@enum::E::@def::1::@getter::c
                     staticType: E
                   SimpleIdentifier
                     token: d @-1
-                    staticElement: self::@enum::E::@getter::d
+                    staticElement: self::@enum::E::@def::1::@getter::d
                     staticType: E
                   SimpleIdentifier
                     token: e @-1
-                    staticElement: self::@enum::E::@getter::e
+                    staticElement: self::@enum::E::@def::1::@getter::e
                     staticType: E
                 rightBracket: ] @0
                 staticType: List<E>
         constructors
           synthetic const @-1
+            reference: self::@enum::E::@def::1::@constructor::new
         accessors
           synthetic static get c @-1
+            reference: self::@enum::E::@def::1::@getter::c
             returnType: E
           synthetic static get d @-1
+            reference: self::@enum::E::@def::1::@getter::d
             returnType: E
           synthetic static get e @-1
+            reference: self::@enum::E::@def::1::@getter::e
             returnType: E
           synthetic static get values @-1
+            reference: self::@enum::E::@def::1::@getter::values
             returnType: List<E>
 ''');
   }
 
   test_duplicateDeclaration_extension() async {
     var library = await buildLibrary(r'''
-class A {}
-extension E on A {}
-extension E on A {
+extension E on int {}
+extension E on int {
   static var x;
 }
-extension E on A {
+extension E on int {
   static var y = 0;
 }
 ''');
+    configuration.withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
-    classes
-      class A @6
-        constructors
-          synthetic @-1
     extensions
-      E @21
-        extendedType: A
-      E @41
-        extendedType: A
+      E @10
+        reference: self::@extension::E::@def::0
+        extendedType: int
+      E @32
+        reference: self::@extension::E::@def::1
+        extendedType: int
         fields
-          static x @63
+          static x @56
+            reference: self::@extension::E::@def::1::@field::x
             type: dynamic
         accessors
           synthetic static get x @-1
+            reference: self::@extension::E::@def::1::@getter::x
             returnType: dynamic
           synthetic static set x= @-1
+            reference: self::@extension::E::@def::1::@setter::x
             parameters
               requiredPositional _x @-1
                 type: dynamic
             returnType: void
-      E @78
-        extendedType: A
+      E @71
+        reference: self::@extension::E::@def::2
+        extendedType: int
         fields
-          static y @100
+          static y @95
+            reference: self::@extension::E::@def::2::@field::y
             type: int
             shouldUseTypeForInitializerInference: false
         accessors
           synthetic static get y @-1
+            reference: self::@extension::E::@def::2::@getter::y
             returnType: int
           synthetic static set y= @-1
+            reference: self::@extension::E::@def::2::@setter::y
             parameters
               requiredPositional _y @-1
                 type: int
@@ -23469,28 +23880,113 @@
 ''');
   }
 
+  test_duplicateDeclaration_extensionType() async {
+    var library = await buildLibrary(r'''
+extension type E(int it) {}
+extension type E(double it) {}
+''');
+    configuration.withReferences = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    extensionTypes
+      E @15
+        reference: self::@extensionType::E::@def::0
+        representation: self::@extensionType::E::@def::0::@field::it
+        primaryConstructor: self::@extensionType::E::@def::0::@constructor::new
+        typeErasure: int
+        interfaces
+          Object
+        fields
+          final it @21
+            reference: self::@extensionType::E::@def::0::@field::it
+            type: int
+        constructors
+          @15
+            reference: self::@extensionType::E::@def::0::@constructor::new
+            parameters
+              requiredPositional final this.it @21
+                type: int
+                field: self::@extensionType::E::@def::0::@field::it
+        accessors
+          synthetic get it @-1
+            reference: self::@extensionType::E::@def::0::@getter::it
+            returnType: int
+      E @43
+        reference: self::@extensionType::E::@def::1
+        representation: self::@extensionType::E::@def::1::@field::it
+        primaryConstructor: self::@extensionType::E::@def::1::@constructor::new
+        typeErasure: double
+        interfaces
+          Object
+        fields
+          final it @52
+            reference: self::@extensionType::E::@def::1::@field::it
+            type: double
+        constructors
+          @43
+            reference: self::@extensionType::E::@def::1::@constructor::new
+            parameters
+              requiredPositional final this.it @52
+                type: double
+                field: self::@extensionType::E::@def::1::@field::it
+        accessors
+          synthetic get it @-1
+            reference: self::@extensionType::E::@def::1::@getter::it
+            returnType: double
+''');
+  }
+
   test_duplicateDeclaration_function() async {
     var library = await buildLibrary(r'''
 void f() {}
 void f(int a) {}
 void f([int b, double c]) {}
 ''');
+    configuration.withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
     functions
       f @5
+        reference: self::@function::f::@def::0
         returnType: void
       f @17
+        reference: self::@function::f::@def::1
         parameters
           requiredPositional a @23
             type: int
         returnType: void
       f @34
+        reference: self::@function::f::@def::2
         parameters
           optionalPositional default b @41
+            reference: self::@function::f::@def::2::@parameter::b
             type: int
           optionalPositional default c @51
+            reference: self::@function::f::@def::2::@parameter::c
+            type: double
+        returnType: void
+''');
+  }
+
+  test_duplicateDeclaration_function_namedParameter() async {
+    var library = await buildLibrary(r'''
+void f({int a, double a}) {}
+''');
+    configuration.withReferences = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    functions
+      f @5
+        reference: self::@function::f
+        parameters
+          optionalNamed default a @12
+            reference: self::@function::f::@parameter::a::@def::0
+            type: int
+          optionalNamed default a @22
+            reference: self::@function::f::@parameter::a::@def::1
             type: double
         returnType: void
 ''');
@@ -23502,15 +23998,18 @@
 typedef void F(int a);
 typedef void F([int b, double c]);
 ''');
+    configuration.withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
     typeAliases
       functionTypeAliasBased F @13
+        reference: self::@typeAlias::F::@def::0
         aliasedType: void Function()
         aliasedElement: GenericFunctionTypeElement
           returnType: void
       functionTypeAliasBased F @31
+        reference: self::@typeAlias::F::@def::1
         aliasedType: void Function(int)
         aliasedElement: GenericFunctionTypeElement
           parameters
@@ -23518,6 +24017,7 @@
               type: int
           returnType: void
       functionTypeAliasBased F @54
+        reference: self::@typeAlias::F::@def::2
         aliasedType: void Function([int, double])
         aliasedElement: GenericFunctionTypeElement
           parameters
@@ -23539,38 +24039,48 @@
   var y = 0;
 }
 ''');
+    configuration.withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
     mixins
       mixin A @6
+        reference: self::@mixin::A::@def::0
         superclassConstraints
           Object
       mixin A @17
+        reference: self::@mixin::A::@def::1
         superclassConstraints
           Object
         fields
           x @27
+            reference: self::@mixin::A::@def::1::@field::x
             type: dynamic
         accessors
           synthetic get x @-1
+            reference: self::@mixin::A::@def::1::@getter::x
             returnType: dynamic
           synthetic set x= @-1
+            reference: self::@mixin::A::@def::1::@setter::x
             parameters
               requiredPositional _x @-1
                 type: dynamic
             returnType: void
       mixin A @38
+        reference: self::@mixin::A::@def::2
         superclassConstraints
           Object
         fields
           y @48
+            reference: self::@mixin::A::@def::2::@field::y
             type: int
             shouldUseTypeForInitializerInference: false
         accessors
           synthetic get y @-1
+            reference: self::@mixin::A::@def::2::@getter::y
             returnType: int
           synthetic set y= @-1
+            reference: self::@mixin::A::@def::2::@setter::y
             parameters
               requiredPositional _y @-1
                 type: int
@@ -23582,52 +24092,154 @@
     var library = await buildLibrary(r'''
 bool x;
 var x;
-var x = 1;
+final x = 1;
 var x = 2.3;
 ''');
+    configuration
+      ..withPropertyLinking = true
+      ..withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
     topLevelVariables
       static x @5
+        reference: self::@variable::x::@def::0
         type: bool
+        id: variable_0
+        getter: getter_0
+        setter: setter_0
       static x @12
+        reference: self::@variable::x::@def::1
         type: dynamic
-      static x @19
+        id: variable_1
+        getter: getter_1
+        setter: setter_1
+      static final x @21
+        reference: self::@variable::x::@def::2
         type: int
         shouldUseTypeForInitializerInference: false
-      static x @30
+        id: variable_2
+        getter: getter_2
+      static x @32
+        reference: self::@variable::x::@def::3
         type: double
         shouldUseTypeForInitializerInference: false
+        id: variable_3
+        getter: getter_3
+        setter: setter_2
     accessors
       synthetic static get x @-1
+        reference: self::@getter::x::@def::0
         returnType: bool
+        id: getter_0
+        variable: variable_0
       synthetic static set x= @-1
+        reference: self::@setter::x::@def::0
         parameters
           requiredPositional _x @-1
             type: bool
         returnType: void
+        id: setter_0
+        variable: variable_0
       synthetic static get x @-1
+        reference: self::@getter::x::@def::1
         returnType: dynamic
+        id: getter_1
+        variable: variable_1
       synthetic static set x= @-1
+        reference: self::@setter::x::@def::1
         parameters
           requiredPositional _x @-1
             type: dynamic
         returnType: void
+        id: setter_1
+        variable: variable_1
       synthetic static get x @-1
+        reference: self::@getter::x::@def::2
         returnType: int
-      synthetic static set x= @-1
-        parameters
-          requiredPositional _x @-1
-            type: int
-        returnType: void
+        id: getter_2
+        variable: variable_2
       synthetic static get x @-1
+        reference: self::@getter::x::@def::3
         returnType: double
+        id: getter_3
+        variable: variable_3
       synthetic static set x= @-1
+        reference: self::@setter::x::@def::2
         parameters
           requiredPositional _x @-1
             type: double
         returnType: void
+        id: setter_2
+        variable: variable_3
+''');
+  }
+
+  test_duplicateDeclaration_unit_getter() async {
+    var library = await buildLibrary(r'''
+int get foo {}
+double get foo {}
+''');
+    configuration
+      ..withPropertyLinking = true
+      ..withReferences = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    topLevelVariables
+      synthetic static foo @-1
+        reference: self::@variable::foo
+        type: double
+        id: variable_0
+        getter: getter_0
+    accessors
+      static get foo @8
+        reference: self::@getter::foo::@def::0
+        returnType: int
+        id: getter_1
+        variable: variable_0
+      static get foo @26
+        reference: self::@getter::foo::@def::1
+        returnType: double
+        id: getter_0
+        variable: variable_0
+''');
+  }
+
+  test_duplicateDeclaration_unit_setter() async {
+    var library = await buildLibrary(r'''
+set foo(int _) {}
+set foo(double _) {}
+''');
+    configuration
+      ..withPropertyLinking = true
+      ..withReferences = true;
+    checkElementText(library, r'''
+library
+  definingUnit
+    topLevelVariables
+      synthetic static foo @-1
+        reference: self::@variable::foo
+        type: double
+        id: variable_0
+        setter: setter_0
+    accessors
+      static set foo= @4
+        reference: self::@setter::foo::@def::0
+        parameters
+          requiredPositional _ @12
+            type: int
+        returnType: void
+        id: setter_1
+        variable: variable_0
+      static set foo= @22
+        reference: self::@setter::foo::@def::1
+        parameters
+          requiredPositional _ @33
+            type: double
+        returnType: void
+        id: setter_0
+        variable: variable_0
 ''');
   }
 
@@ -24069,14 +24681,17 @@
   const E(this.x);
 }
 ''');
+    configuration.withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
     enums
       enum E @5
+        reference: self::@enum::E
         supertype: Enum
         fields
           static const enumConstant v @11
+            reference: self::@enum::E::@field::v
             type: E
             shouldUseTypeForInitializerInference: false
             constantInitializer
@@ -24092,6 +24707,7 @@
                   rightParenthesis: ) @0
                 staticType: E
           synthetic static const values @-1
+            reference: self::@enum::E::@field::values
             type: List<E>
             constantInitializer
               ListLiteral
@@ -24104,23 +24720,30 @@
                 rightBracket: ] @0
                 staticType: List<E>
           final x @26
+            reference: self::@enum::E::@field::x::@def::0
             type: int
           final x @44
+            reference: self::@enum::E::@field::x::@def::1
             type: String
         constructors
           const @55
+            reference: self::@enum::E::@constructor::new
             parameters
               requiredPositional final this.x @62
                 type: int
-                field: self::@enum::E::@field::x
+                field: self::@enum::E::@field::x::@def::0
         accessors
           synthetic static get v @-1
+            reference: self::@enum::E::@getter::v
             returnType: E
           synthetic static get values @-1
+            reference: self::@enum::E::@getter::values
             returnType: List<E>
           synthetic get x @-1
+            reference: self::@enum::E::@getter::x::@def::0
             returnType: int
           synthetic get x @-1
+            reference: self::@enum::E::@getter::x::@def::1
             returnType: String
 ''');
   }
@@ -29211,20 +29834,33 @@
   test_implicitTopLevelVariable_getterFirst() async {
     var library =
         await buildLibrary('int get x => 0; void set x(int value) {}');
+    configuration
+      ..withPropertyLinking = true
+      ..withReferences = true;
     checkElementText(library, r'''
 library
   definingUnit
     topLevelVariables
       synthetic static x @-1
+        reference: self::@variable::x
         type: int
+        id: variable_0
+        getter: getter_0
+        setter: setter_0
     accessors
       static get x @8
+        reference: self::@getter::x
         returnType: int
+        id: getter_0
+        variable: variable_0
       static set x= @25
+        reference: self::@setter::x
         parameters
           requiredPositional value @31
             type: int
         returnType: void
+        id: setter_0
+        variable: variable_0
 ''');
   }
 
diff --git a/pkg/analyzer/test/src/summary/reference_test.dart b/pkg/analyzer/test/src/summary/reference_test.dart
index 67cdf03..a5661fc 100644
--- a/pkg/analyzer/test/src/summary/reference_test.dart
+++ b/pkg/analyzer/test/src/summary/reference_test.dart
@@ -6,6 +6,9 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import '../../util/tree_string_sink.dart';
+import '../dart/resolution/node_text_expectations.dart';
+
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ReferenceTest);
@@ -14,107 +17,266 @@
 
 @reflectiveTest
 class ReferenceTest {
-  void test_addingAndRemoving() {
-    Reference root = Reference.root();
+  final _IdMap idMap = _IdMap();
 
-    // First child: foo.
-    final firstCallFoo = root.getChild("foo");
-    final secondCallFoo = root.getChild("foo");
-    final thirdCallFoo = root["foo"];
-    expect(secondCallFoo, same(firstCallFoo));
-    expect(thirdCallFoo, same(firstCallFoo));
-    expect(firstCallFoo.name, "foo");
-    expect(root.childrenUnionForTesting, same(firstCallFoo));
-    expect(root.children, hasLength(1));
+  void assertReferenceText(Reference reference, String expected) {
+    final buffer = StringBuffer();
+    _ReferenceWriter(
+      sink: TreeStringSink(
+        sink: buffer,
+        indent: '',
+      ),
+      idMap: idMap,
+    ).write(reference);
+    final actual = buffer.toString();
 
-    // Second child: bar.
-    final firstCallBar = root.getChild("bar");
-    final secondCallBar = root.getChild("bar");
-    final thirdCallBar = root["bar"];
-    expect(secondCallBar, same(firstCallBar));
-    expect(thirdCallBar, same(firstCallBar));
-    expect(firstCallBar.name, "bar");
-    expect(root.childrenUnionForTesting, isA<Map<String, Reference>>());
-    expect(root.children, hasLength(2));
-
-    // Asking again returns the same.
-    {
-      final foo1 = root.getChild("foo");
-      final foo2 = root["foo"];
-      final bar1 = root.getChild("bar");
-      final bar2 = root["bar"];
-      expect(foo1, same(firstCallFoo));
-      expect(foo2, same(firstCallFoo));
-      expect(bar1, same(firstCallBar));
-      expect(bar2, same(firstCallBar));
-      expect(root.childrenUnionForTesting, isA<Map<String, Reference>>());
+    if (actual != expected) {
+      print('-------- Actual --------');
+      print('$actual------------------------');
+      NodeTextExpectationsCollector.add(actual);
     }
-
-    // Foo can have children.
-    {
-      final foo = root.getChild("foo");
-      expect(foo.childrenUnionForTesting, isNull);
-      final fooChild1 = foo.getChild("child1");
-      expect(foo.childrenUnionForTesting, same(fooChild1));
-      final fooChild1Again = foo.getChild("child1");
-      expect(foo.childrenUnionForTesting, same(fooChild1));
-      final fooChild2 = foo.getChild("child2");
-      expect(foo.childrenUnionForTesting, isA<Map<String, Reference>>());
-      final fooChild2Again = foo.getChild("child2");
-      expect(foo.childrenUnionForTesting, isA<Map<String, Reference>>());
-      expect(foo, same(firstCallFoo));
-      expect(fooChild1, same(fooChild1Again));
-      expect(fooChild1.name, "child1");
-      expect(fooChild2, same(fooChild2Again));
-      expect(fooChild2.name, "child2");
-      expect(foo.children, hasLength(2));
-    }
-
-    // Removing foo works, retains bar, and root then has 1 child.
-    {
-      final foo1 = root.removeChild("foo");
-      final foo2 = root["foo"];
-      final bar1 = root.getChild("bar");
-      final bar2 = root["bar"];
-      expect(foo1, same(firstCallFoo));
-      expect(foo1!.children, hasLength(2));
-      expect(foo2, isNull);
-      expect(bar1, same(firstCallBar));
-      expect(bar2, same(firstCallBar));
-      expect(root.children, hasLength(1));
-      expect(root.childrenUnionForTesting, isA<Reference>());
-      expect(root.childrenUnionForTesting, same(firstCallBar));
-    }
-
-    // Re-adding a foo is different than the initial one.
-    {
-      expect(root.childrenUnionForTesting, same(firstCallBar));
-      final foo1 = root.getChild("foo");
-      expect(root.childrenUnionForTesting, isA<Map<String, Reference>>());
-      final foo2 = root["foo"];
-      final bar1 = root.getChild("bar");
-      final bar2 = root["bar"];
-      expect(foo1.children, hasLength(0));
-      expect(foo1.name, "foo");
-      expect(identical(foo1, firstCallFoo), isFalse);
-      expect(foo2, same(foo1));
-      expect(bar1, same(firstCallBar));
-      expect(bar2, same(firstCallBar));
-      expect(root.children, hasLength(2));
-    }
+    expect(actual, expected);
   }
 
-  void test_rootDoesntContainFooBeforeAdded() {
-    Reference root = Reference.root();
-    expect(root["foo"], isNull);
-    expect(root["foo"], isNull);
-    expect(root.children, isEmpty);
-    expect(root.childrenUnionForTesting, isNull);
+  void test_addChild() {
+    final root = Reference.root();
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+''');
+
+    final foo1 = root.addChild('foo');
+    expect(foo1.elementName, 'foo');
+    expect(idMap[foo1], 'r1');
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+  childrenUnion: r1
+  children
+    foo
+      id: r1
+''');
+
+    final foo2 = root.addChild('foo');
+    expect(foo2.elementName, 'foo');
+    expect(idMap[foo1], 'r1');
+    expect(idMap[foo2], 'r2');
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+  childrenUnion: r3
+  children
+    foo
+      id: r3
+      childrenUnion: r4
+      children
+        @def
+          id: r4
+          childrenUnion: {0: r1, 1: r2}
+          children
+            0
+              id: r1
+            1
+              id: r2
+''');
+
+    final foo3 = root.addChild('foo');
+    expect(foo3.elementName, 'foo');
+    expect(idMap[foo1], 'r1');
+    expect(idMap[foo2], 'r2');
+    expect(idMap[foo3], 'r5');
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+  childrenUnion: r3
+  children
+    foo
+      id: r3
+      childrenUnion: r4
+      children
+        @def
+          id: r4
+          childrenUnion: {0: r1, 1: r2, 2: r5}
+          children
+            0
+              id: r1
+            1
+              id: r2
+            2
+              id: r5
+''');
   }
 
-  void test_rootInitiallyEmpty() {
-    Reference root = Reference.root();
-    expect(root.children, isEmpty);
-    expect(root.childrenUnionForTesting, isNull);
+  void test_getChild() {
+    final root = Reference.root();
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+''');
+
+    // 0 -> 1
+    {
+      final first = root.getChild('foo');
+      final second = root.getChild('foo');
+      final third = root['foo'];
+      expect(second, same(first));
+      expect(third, same(first));
+      expect(idMap[first], 'r1');
+    }
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+  childrenUnion: r1
+  children
+    foo
+      id: r1
+''');
+
+    // 1 -> 2
+    {
+      final first = root.getChild('bar');
+      final second = root.getChild('bar');
+      final third = root['bar'];
+      expect(second, same(first));
+      expect(third, same(first));
+      expect(idMap[first], 'r2');
+    }
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+  childrenUnion: {foo: r1, bar: r2}
+  children
+    foo
+      id: r1
+    bar
+      id: r2
+''');
+  }
+
+  void test_indexRead() {
+    final root = Reference.root();
+    expect(root['foo'], isNull);
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+''');
+  }
+
+  void test_remove() {
+    final root = Reference.root();
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+''');
+
+    final foo = root.getChild('foo');
+    final bar = root.getChild('bar');
+    final baz = root.getChild('baz');
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+  childrenUnion: {foo: r1, bar: r2, baz: r3}
+  children
+    foo
+      id: r1
+    bar
+      id: r2
+    baz
+      id: r3
+''');
+
+    // 3 -> 2
+    final bar2 = root.removeChild('bar');
+    expect(bar2, same(bar));
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+  childrenUnion: {foo: r1, baz: r3}
+  children
+    foo
+      id: r1
+    baz
+      id: r3
+''');
+
+    // 2 -> 1
+    final baz2 = root.removeChild('baz');
+    expect(baz2, same(baz));
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+  childrenUnion: r1
+  children
+    foo
+      id: r1
+''');
+
+    // 1 -> 0
+    final foo2 = root.removeChild('foo');
+    expect(foo2, same(foo));
+    assertReferenceText(root, r'''
+<root>
+  id: r0
+''');
+
+    final foo3 = root.removeChild('foo');
+    expect(foo3, isNull);
+  }
+}
+
+class _IdMap {
+  final Map<Reference, String> map = Map.identity();
+
+  String operator [](Reference reference) {
+    return map[reference] ??= 'r${map.length}';
+  }
+}
+
+class _ReferenceWriter {
+  final TreeStringSink sink;
+  final _IdMap idMap;
+
+  _ReferenceWriter({
+    required this.sink,
+    required this.idMap,
+  });
+
+  void write(Reference reference) {
+    if (reference.isRoot) {
+      sink.writelnWithIndent('<root>');
+    } else {
+      sink.writelnWithIndent(reference.name);
+    }
+
+    sink.withIndent(() {
+      sink.writelnWithIndent('id: ${idMap[reference]}');
+
+      final union = reference.childrenUnionForTesting;
+      if (union != null) {
+        sink.writeIndentedLine(() {
+          sink.write('childrenUnion: ');
+          switch (union) {
+            case Reference child:
+              expect(reference.children, hasLength(1));
+              sink.write(idMap[child]);
+            case Map<String, Reference> map:
+              expect(reference.children, hasLength(greaterThanOrEqualTo(2)));
+              final entriesStr = map.entries.map((e) {
+                return '${e.key}: ${idMap[e.value]}';
+              }).join(', ');
+              sink.write('{$entriesStr}');
+            default:
+              throw UnimplementedError('(${union.runtimeType}) $union');
+          }
+        });
+      }
+
+      // Sanity check.
+      for (final child in reference.children) {
+        expect(child.parent, same(reference));
+      }
+
+      sink.writeElements('children', reference.children.toList(), write);
+    });
   }
 }