FieldReference listToFieldEntries()

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