in packages/devtools_app/lib/src/memory/memory_snapshot_models.dart [846:1025]
FieldReference listToFieldEntries(
MemoryController controller,
HeapGraphElement reference,
String fieldName,
int size, {
isHashMap = false,
}) {
bool isAMap = false;
HeapGraphElementLive actualListElement;
ObjectFieldReference listObjectReference;
if (reference is HeapGraphElementLive) {
final actualListClass = reference.theClass as HeapGraphClassLive;
if (isBuiltInList(actualListClass)) {
// Add the list entry.
actualListElement = reference;
listObjectReference = ObjectFieldReference(
controller,
actualListElement,
isHashMap ? 'HashMap' : 'List',
isHashMap ? '$fieldName {$size}' : '[$size]',
);
} else if (isBuiltInMap(actualListClass)) {
// Add the Map field name and the key/value pairs.
actualListElement = reference;
listObjectReference = ObjectFieldReference(
controller,
actualListElement,
'Map',
'$fieldName { ${size ~/ 2} }',
);
// Look for list of Map values.
for (final reference in actualListElement.references) {
if (reference is HeapGraphElementLive) {
final HeapGraphClassLive theClass = reference.theClass;
final fullClassName = theClass.fullQualifiedName;
if (fullClassName == predefinedList) {
actualListElement = reference;
isAMap = true;
break;
}
}
}
}
}
assert(listObjectReference != null);
var listIndex = 0;
final allEntryReferences = actualListElement.references;
final referencesLength = allEntryReferences.length;
// Find all the Map key/value pairs (for integer keys the key maybe missing).
// TODO(terry): Need to verify.
final List<HeapGraphElement> realEntries = [];
for (var entryElementIndex = 0;
entryElementIndex < referencesLength;
entryElementIndex++) {
final entry = allEntryReferences[entryElementIndex];
if (entry is HeapGraphElementLive) {
final HeapGraphElementLive entryElement = entry;
final HeapGraphClassLive actualClass = entryElement.theClass;
if (actualClass.fullQualifiedName != predefinedNull) {
realEntries.add(entryElement);
}
}
}
// TODO(terry): Need to verify.
// Only value key if size != to number of real entries.
final hasKeyValues = isAMap && realEntries.length == size;
for (var realEntryIndex = 0;
realEntryIndex < realEntries.length;
realEntryIndex++) {
final entryElement = realEntries[realEntryIndex];
if (entryElement is HeapGraphElementLive) {
final entryClass = entryElement.theClass;
if (entryClass is HeapGraphClassLive &&
entryClass.fullQualifiedName != predefinedNull) {
final predefined = predefinedClasses[entryClass.fullQualifiedName];
FieldReference listEntry;
if (predefined != null && predefined.isScalar) {
if (isAMap) {
if (hasKeyValues) {
final HeapGraphElementLive valueElement =
realEntries[realEntryIndex + 1];
realEntryIndex++;
// The value entry is computed on key expansion.
var predefined = predefinedClasses[entryClass.fullQualifiedName];
listEntry = ObjectFieldReference(
controller,
entryElement,
'${predefined.prettyName}',
'key \'${entryElement.origin.data}\'',
);
FieldReference valueEntry;
final HeapGraphClassLive valueClass = valueElement.theClass;
predefined = predefinedClasses[valueClass.fullQualifiedName];
if (predefined != null && predefined.isScalar) {
valueEntry = createScalar(controller, 'value', valueElement);
} else {
valueEntry = ObjectFieldReference(
controller,
valueElement,
valueClass.name,
'value',
);
// Compute the object's fields when onExpand hit.
valueEntry.addChild(FieldReference.empty);
}
listEntry.addChild(valueEntry);
} else {
// This is the value w/o any idea the index is the key.
listEntry =
createScalar(controller, 'value $listIndex', entryElement);
}
} else {
// Display the scalar entry.
listEntry = createScalar(controller, fieldName, entryElement);
}
} else {
listEntry ??= ObjectFieldReference(
controller,
entryElement,
entryClass.name,
'[$listIndex]',
);
if (entryElement.references.isNotEmpty) {
// Key of the Map is an object.
if (isAMap) {
final keyFields = entryElement.getFields();
for (final keyField in keyFields) {
final key = keyField.key;
final value = keyField.value;
// Skip sentinels and null values.
if (!value.isSentinel && !dataIsNull(value)) {
final HeapGraphElementLive live = value;
final HeapGraphClassLive theClass = live.theClass;
final className = theClass.fullQualifiedName;
final predefined = predefinedClasses[className];
if (predefined != null && predefined.isScalar) {
final scalarEntry = createScalar(controller, key, live);
listEntry.addChild(scalarEntry);
} else {
final keyObjectRef = ObjectFieldReference(
controller,
live,
theClass.name,
'$key',
);
keyObjectRef.addChild(FieldReference.empty);
listEntry.addChild(keyObjectRef);
}
}
}
}
}
}
// Entry type to expand later.
if (!isAMap) {
listEntry.addChild(FieldReference.empty);
}
// Add our [n] entry.
listObjectReference.addChild(listEntry);
// TODO(terry): Consider showing all entries - is it useful?
// Add each entry to the list, up to 100.
if (listIndex++ > 100) break;
}
}
}
return listObjectReference;
}