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);
+ });
}
}