private IEnumerable GetChildrenImpl()

in debugger/debugger-worker/src/Values/Render/ChildrenRenderers/SerialisedPropertyChildrenRenderer.cs [71:160]


        private IEnumerable<IValueEntity> GetChildrenImpl(IObjectValueRole<TValue> valueRole,
                                                          IMetadataTypeLite instanceType,
                                                          IPresentationOptions options,
                                                          IUserDataHolder dataHolder,
                                                          CancellationToken token)
        {
            var enumValueObject = valueRole.GetInstancePropertyReference("propertyType")
                ?.AsObjectSafe(options)?.GetEnumValue(options);
            var propertyType = (SerializedPropertyKind) Enum.ToObject(typeof(SerializedPropertyKind),
                enumValueObject ?? SerializedPropertyKind.Invalid);

            // Fall back to showing everything if we don't have any special handling for the property type. This should
            // protect us if Unity introduces a new serialised property type.
            if (!myHandledPropertyTypes.Contains(propertyType))
            {
                foreach (var valueEntity in base.GetChildren(valueRole, instanceType, options, dataHolder, token))
                    yield return valueEntity;
                yield break;
            }

            var propertySpecificFields = myPerTypeFieldNames[propertyType];

            var isArray = false;
            var isFixedBuffer = false;

            // Generic means a custom serializable struct, an array or a fixed buffer (public unsafe fixed int buf[10])
            // Strings are also arrays, and have properties for each character. We'll show them too.
            if (propertyType == SerializedPropertyKind.Generic || propertyType == SerializedPropertyKind.String)
            {
                if (!Util.TryEvaluatePrimitiveProperty(valueRole, "isArray", options, out isArray) || !isArray)
                    Util.TryEvaluatePrimitiveProperty(valueRole, "isFixedBuffer", options, out isFixedBuffer);
            }

            // We filter all non-public members, so make sure we don't show the group
            var effectiveOptions = options.WithOverridden(o => o.GroupPrivateMembers = false);

            var references = EnumerateChildren(valueRole, effectiveOptions, token);
            references = FilterChildren(references, propertySpecificFields, isArray, isFixedBuffer);
            references = DecorateChildren(valueRole, references, propertyType, options);
            references = SortChildren(references);
            foreach (var valueEntity in RenderChildren(valueRole, references, effectiveOptions, token))
                yield return valueEntity;

            if (!Util.TryEvaluatePrimitiveProperty(valueRole, "hasChildren", options, out bool hasChildren))
                Logger.Warn("Cannot evaluate hasChildren for serializedProperty");
            else if (hasChildren)
            {
                // Arrays, fixed buffer arrays and strings (which are arrays) all say they have children. They don't.
                // They have a special sibling (i.e. same depth) that can only be enumerated with Next(true), and is
                // skipped with Next(false).
                // We don't show these special siblings, because they're not children, and the data is already displayed
                // as part of the array/fixed buffer element group.
                // TODO: Should we show this?
                // It might be confusing if these special properties are never shown, especially if someone is using
                // the debugger to try to figure out the shape of the serialised stream. The question is, how do we show
                // something that is enumerated as a child, but stored as a sibling? The best solution is a dump of the
                // whole serialised stream, which is not what we're doing as part of the debugger. One solution would be
                // to add an "Array" node that is shown instead of "Children" - but that would still look like a child
                // node, and would only include the "Size" node over the existing array/fixed buffer element group.
                // For now, just ignore these special properties and leave it to the array/fixed buffer element group.
                if (!isArray && !isFixedBuffer && propertyType != SerializedPropertyKind.String)
                    yield return new ChildrenGroup(valueRole, ValueServices, Logger);
            }

            if (isArray)
            {
                if (!Util.TryEvaluatePrimitiveProperty(valueRole, "arraySize", options, out int arraySize))
                    Logger.Warn("Cannot evaluate arraySize for serializedProperty");
                else if (arraySize > 0)
                {
                    yield return new ArrayElementsGroup(valueRole, arraySize,
                        MethodSelectors.SerializedProperty_GetArrayElementAtIndex, ValueServices, Logger);
                }
            }
            else if (isFixedBuffer)
            {
                if (!Util.TryEvaluatePrimitiveProperty(valueRole, "fixedBufferSize", options, out int fixedBufferSize))
                    Logger.Warn("Cannot evaluate fixedBufferSize for serializedProperty");
                else if (fixedBufferSize > 0)
                {
                    yield return new ArrayElementsGroup(valueRole, fixedBufferSize,
                        MethodSelectors.SerializedProperty_GetFixedBufferElementAtIndex, ValueServices, Logger);
                }
            }

            // Disable debugger type proxy options to avoid recursion. See IsApplicable.
            var rawViewOptions = options.WithOverridden(o => o.EvaluateDebuggerTypeProxy = false);
            yield return new SimpleEntityGroup(PresentationOptions.RawViewGroupName,
                valueRole.ValueReference.ToValue(ValueServices).GetChildren(rawViewOptions, token));
        }