Exemple #1
0
        void CollectObjectSegment(INamedTypeSymbol type, bool fromNullable, bool asKey)
        {
            if (type == null)
            {
                return;
            }
            if (!alreadyCollected.Add(Tuple.Create(type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), fromNullable, asKey)))
            {
                return;
            }
            if (KnownFormatterSpec.IsPrimitive(type))
            {
                return;
            }
            if (type.GetAttributes().FindAttributeShortName(UnionAttributeShortName) != null)
            {
                return;
            }

            if (type.GetAttributes().FindAttributeShortName(DynamicUnionAttributeShortName) != null)
            {
                return;
            }
            if (type.TypeKind == TypeKind.Enum)
            {
                CollectEnum(type, fromNullable, asKey);
                return;
            }
            if (allowCustomTypes.Contains(type.ToDisplayString()))
            {
                return;
            }

            if (disallowInMetadata && type.Locations[0].IsInMetadata)
            {
                return;
            }

            if (!IsAllowType(type))
            {
                return;
            }

            if (type.IsGenericType)
            {
                var genericType       = type.ConstructUnboundGenericType();
                var genericTypeString = genericType.ToDisplayString();

                if (genericTypeString == "T?")
                {
                    CollectObjectSegment(type.TypeArguments[0] as INamedTypeSymbol, true, asKey);
                    return;
                }
                else if (allowCustomTypes.Contains(genericTypeString))
                {
                    foreach (var t in type.TypeArguments)
                    {
                        CollectObjectSegment(t as INamedTypeSymbol, fromNullable, asKey);
                    }
                    return;
                }
                else if (genericTypeString == "System.Collections.Generic.IList<>" ||
                         genericTypeString == "System.Collections.Generic.IDictionary<,>" ||
                         genericTypeString == "System.Collections.Generic.Dictionary<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyDictionary<,>" ||
                         genericTypeString == "System.Collections.Generic.IReadOnlyList<>" ||
                         genericTypeString == "System.Collections.Generic.ICollection<>" ||
                         genericTypeString == "System.Collections.Generic.IEnumerable<>" ||
                         genericTypeString == "System.Collections.Generic.ISet<>" ||
                         genericTypeString == "ZeroFormatter.ILazyReadOnlyDictionary<,>" ||
                         genericTypeString == "System.Collections.ObjectModel.ReadOnlyCollection<>" ||
                         genericTypeString == "System.Linq.ILookup<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyLookup<,>" ||
                         genericTypeString.StartsWith("System.Collections.Generic.KeyValuePair") ||
                         genericTypeString.StartsWith("ZeroFormatter.KeyTuple"))
                {
                    var elementTypes    = string.Join(", ", type.TypeArguments.Select(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));
                    var isDictionaryKey = false;

                    if (genericTypeString == "System.Collections.Generic.IList<>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.List, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IReadOnlyList<>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.ReadOnlyList, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IDictionary<,>" || genericTypeString == "System.Collections.Generic.Dictionary<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Dictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyDictionary<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyReadOnlyDictionary<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyReadOnlyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyLookup<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyLookup, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Linq.ILookup<,>")
                    {
                        isDictionaryKey = true;
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Lookup, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("ZeroFormatter.KeyTuple"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.KeyTuple, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("System.Collections.Generic.KeyValuePair"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.KeyValuePair, ElementTypes = elementTypes
                        });
                    }

                    else if (genericTypeString.StartsWith("System.Collections.Generic.ICollection<>"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.InterfaceCollection, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("System.Collections.Generic.IEnumerable<>"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Enumerable, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("System.Collections.ObjectModel.ReadOnlyCollection<>"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.ReadOnlyCollection, ElementTypes = elementTypes
                        });
                    }

                    var argIndex = 0;
                    foreach (var t in type.TypeArguments)
                    {
                        if (isDictionaryKey && argIndex == 0)
                        {
                            CollectObjectSegment(t as INamedTypeSymbol, fromNullable, true);
                        }
                        else
                        {
                            CollectObjectSegment(t as INamedTypeSymbol, fromNullable, asKey);
                        }
                        argIndex++;
                    }
                    return;
                }
                else if (type.AllInterfaces.Any(x => (x.IsGenericType ? x.ConstructUnboundGenericType().ToDisplayString() : "") == "System.Collections.Generic.ICollection<>"))
                {
                    var elementTypes = string.Join(", ", type.TypeArguments.Select(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))) + ", " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                    genericTypeContainer.Add(new GenericType {
                        TypeKind = GenericTypeKind.Collection, ElementTypes = elementTypes
                    });

                    foreach (var t in type.TypeArguments)
                    {
                        CollectObjectSegment(t as INamedTypeSymbol, fromNullable, asKey);
                    }
                    return;
                }
            }

            if (type.GetAttributes().FindAttributeShortName(ZeroFormattableAttributeShortName) == null)
            {
                throw new Exception($"Type must be marked with ZeroFormattableAttribute. {type.Name}.  Location:{type.Locations[0]}");
            }

            if (!type.IsValueType)
            {
                if (!type.Constructors.Any(x => x.Parameters.Length == 0))
                {
                    throw new Exception($"Type must needs parameterless constructor. {type.Name}. Location:{type.Locations[0]}");
                }
            }
            else
            {
                var indexes = new List <Tuple <int, IPropertySymbol> >();
                foreach (var item in type.GetMembers().OfType <IPropertySymbol>())
                {
                    if (item.IsStatic)
                    {
                        continue;
                    }
                    if (item.ExplicitInterfaceImplementations.Length != 0)
                    {
                        continue;
                    }

                    var indexAttr = item.GetAttributes().FindAttributeShortName(IndexAttributeShortName);
                    if (indexAttr != null)
                    {
                        var index = (int)indexAttr.ConstructorArguments[0].Value;
                        indexes.Add(Tuple.Create(index, item));
                    }
                }
                indexes = indexes.OrderBy(x => x.Item1).ToList();

                var expected = 0;
                foreach (var item in indexes)
                {
                    if (item.Item1 != expected)
                    {
                        throw new Exception($"Struct index must be started with 0 and be sequential. Type: {type.Name}, InvalidIndex: {item.Item1}");
                    }
                    expected++;
                }

                var foundConstructor = false;
                var ctors            = (type as INamedTypeSymbol)?.Constructors;
                foreach (var ctor in ctors)
                {
                    var isMatch = indexes.Select(x => x.Item2.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
                                  .SequenceEqual(ctor.Parameters.Select(x => x.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));
                    if (isMatch)
                    {
                        foundConstructor = true;
                    }
                }
                if (!foundConstructor && indexes.Count != 0)
                {
                    throw new Exception($"Struct needs full parameter constructor of index property types. Type: {type.Name}");
                }
            }

            var list = new List <ObjectSegmentType.PropertyTuple>();

            var definedIndexes = new HashSet <int>();

            var distinctName = new HashSet <string>();

            foreach (var property in type.GetAllMembers())
            {
                if (!distinctName.Add(property.Name))
                {
                    continue;
                }


                if (property.IsStatic)
                {
                    continue;
                }

                var propSymbol  = property as IPropertySymbol;
                var fieldSymbol = property as IFieldSymbol;

                if ((propSymbol == null && fieldSymbol == null))
                {
                    continue;
                }

                if (property.DeclaredAccessibility != Accessibility.Public)
                {
                    continue;
                }

                if (propSymbol != null && propSymbol.ExplicitInterfaceImplementations.Length != 0)
                {
                    continue;
                }

                var attributes = property.GetAttributes();
                if (attributes.FindAttributeShortName(IgnoreAttributeShortName) != null)
                {
                    continue;
                }

                if (!type.IsValueType)
                {
                    if (!property.IsVirtual)
                    {
                        if (property.IsOverride && !property.IsSealed)
                        {
                            // okay, it is override property.
                        }
                        else
                        {
                            throw new Exception($"Public property's accessor must be virtual. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                        }
                    }
                }

                if (propSymbol != null && propSymbol.FindAttributeIncludeBasePropertyShortName(UnionKeyAttributeShortName) != null)
                {
                    continue;
                }

                var indexAttr = attributes.FindAttributeShortName(IndexAttributeShortName);
                if (indexAttr == null || indexAttr.ConstructorArguments.Length == 0)
                {
                    throw new Exception($"Public property must be marked with IndexAttribute or IgnoreFormatAttribute. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                }

                var index = indexAttr.ConstructorArguments[0];
                if (index.IsNull)
                {
                    continue; // null is normal compiler error.
                }

                if (!definedIndexes.Add((int)index.Value))
                {
                    throw new Exception($"IndexAttribute is not allow duplicate number. {type.Name}.{property.Name}, Index:{index.Value} Location:{type.Locations[0]}");
                }

                if (!type.IsValueType)
                {
                    if (propSymbol == null)
                    {
                        throw new Exception($"Class does not allow that field marks IndexAttribute. {type.Name }{property.Name}");
                    }

                    if (propSymbol.GetMethod == null || propSymbol.SetMethod == null ||
                        propSymbol.GetMethod.DeclaredAccessibility == Accessibility.Private ||
                        propSymbol.SetMethod.DeclaredAccessibility == Accessibility.Private)
                    {
                        throw new Exception($"Public property must needs both public/protected get and set accessor. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                    }
                }

                var memberType = (propSymbol != null) ? propSymbol.Type : fieldSymbol.Type;

                if (memberType.TypeKind == TypeKind.Array)
                {
                    var array = memberType as IArrayTypeSymbol;
                    while (array != null)
                    {
                        var t = array.ElementType;
                        if (!KnownFormatterSpec.AllowArrayType(t))
                        {
                            genericTypeContainer.Add(new GenericType {
                                TypeKind = GenericTypeKind.Array, ElementTypes = t.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
                            });
                        }

                        var namedType = t as INamedTypeSymbol;
                        if (namedType != null && namedType.Kind != SymbolKind.ArrayType) // if <T> is unnamed type, it can't analyze.
                        {
                            // Recursive
                            CollectObjectSegment(namedType, fromNullable, asKey);
                            break;
                        }
                        array = t as IArrayTypeSymbol;
                    }
                }
                else
                {
                    var namedType = memberType as INamedTypeSymbol;
                    if (namedType != null) // if <T> is unnamed type, it can't analyze.
                    {
                        // Recursive
                        CollectObjectSegment(namedType, fromNullable, asKey);
                    }
                }

                var length = KnownFormatterSpec.GetLength(memberType);
                var prop   = new ObjectSegmentType.PropertyTuple
                {
                    Name           = property.Name,
                    Type           = memberType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                    Index          = (int)index.Value,
                    IsGetProtected = (propSymbol != null) ? propSymbol?.GetMethod?.DeclaredAccessibility == Accessibility.Protected : false,
                    IsSetProtected = (propSymbol != null) ? propSymbol?.SetMethod?.DeclaredAccessibility == Accessibility.Protected : false,
                    FixedSize      = length ?? 0,
                    IsProperty     = propSymbol != null,
                    IsCacheSegment = !KnownFormatterSpec.IsLazySegment(memberType),
                    IsFixedSize    = (length != null)
                };

                list.Add(prop);
            }

            var segment = new ObjectSegmentType
            {
                Name       = type.ToDisplayString(typeNameFormat).Replace(".", "_"),
                FullName   = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                Namespace  = type.ContainingNamespace.IsGlobalNamespace ? null : type.ContainingNamespace.ToDisplayString(),
                LastIndex  = list.Select(x => x.Index).DefaultIfEmpty(0).Max(),
                Properties = list.OrderBy(x => x.Index).ToArray(),
            };

            if (type.IsValueType)
            {
                structContainer.Add(segment);
            }
            else
            {
                objectContainer.Add(segment);
            }
        }
        void CollectObjectSegment(INamedTypeSymbol type)
        {
            if (type == null)
            {
                return;
            }
            if (!alreadyCollected.Add(type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)))
            {
                return;
            }
            if (KnownFormatterSpec.IsPrimitive(type))
            {
                return;
            }
            if (type.TypeKind == TypeKind.Enum)
            {
                CollectEnum(type);
                return;
            }
            if (type.IsGenericType)
            {
                var genericType       = type.ConstructUnboundGenericType();
                var genericTypeString = genericType.ToDisplayString();

                if (genericTypeString == "T?")
                {
                    CollectObjectSegment(type.TypeArguments[0] as INamedTypeSymbol);
                    return;
                }
                else if (genericTypeString == "System.Collections.Generic.List<>")
                {
                    throw new Exception($"List does not support in ZeroFormatter because List have to deserialize all objects. You can use IList<T> instead of List. {type.Name}.");
                }
                else if (genericTypeString == "System.Collections.Generic.Dictionary<,>")
                {
                    throw new Exception($"Dictionary does not support in ZeroFormatter because Dictionary have to deserialize all objects. You can use IDictionary<TK, TV> instead of Dictionary. {type.Name}.");
                }
                else if (genericTypeString == "System.Collections.Generic.IList<>" ||
                         genericTypeString == "System.Collections.Generic.IDictionary<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyDictionary<,>" ||
                         genericTypeString == "System.Collections.Generic.IReadOnlyList<>" ||
                         genericTypeString == "System.Collections.Generic.IReadOnlyDictionary<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyReadOnlyDictionary<,>" ||
                         genericTypeString == "System.Linq.ILookup<,>" ||
                         genericTypeString == "ZeroFormatter.ILazyLookup<,>" ||
                         genericTypeString.StartsWith("ZeroFormatter.KeyTuple"))
                {
                    var elementTypes = string.Join(", ", type.TypeArguments.Select(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));

                    if (genericTypeString == "System.Collections.Generic.IList<>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.List, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IReadOnlyList<>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.ReadOnlyList, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IDictionary<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Dictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Collections.Generic.IReadOnlyDictionary<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.ReadOnlyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyDictionary<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyReadOnlyDictionary<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyReadOnlyDictionary, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "ZeroFormatter.ILazyLookup<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.LazyLookup, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString == "System.Linq.ILookup<,>")
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.Lookup, ElementTypes = elementTypes
                        });
                    }
                    else if (genericTypeString.StartsWith("ZeroFormatter.KeyTuple"))
                    {
                        genericTypeContainer.Add(new GenericType {
                            TypeKind = GenericTypeKind.KeyTuple, ElementTypes = elementTypes
                        });
                    }

                    foreach (var t in type.TypeArguments)
                    {
                        CollectObjectSegment(t as INamedTypeSymbol);
                    }
                    return;
                }
            }

            if (type.GetAttributes().FindAttributeShortName(ZeroFormattableAttributeShortName) == null)
            {
                throw new Exception($"Type must mark ZeroFormattableAttribute. {type.Name}.  Location:{type.Locations[0]}");
            }

            if (!type.IsValueType)
            {
                if (!type.Constructors.Any(x => x.Parameters.Length == 0))
                {
                    throw new Exception($"Type must needs parameterless constructor. {type.Name}. Location:{type.Locations[0]}");
                }
            }
            else
            {
                var indexes = new List <Tuple <int, IPropertySymbol> >();
                foreach (var item in type.GetMembers().OfType <IPropertySymbol>())
                {
                    var indexAttr = item.GetAttributes().FindAttributeShortName(IndexAttributeShortName);
                    if (indexAttr != null)
                    {
                        var index = (int)indexAttr.ConstructorArguments[0].Value;
                        indexes.Add(Tuple.Create(index, item));
                    }
                }
                indexes = indexes.OrderBy(x => x.Item1).ToList();

                var expected = 0;
                foreach (var item in indexes)
                {
                    if (item.Item1 != expected)
                    {
                        throw new Exception($"Struct index must be started with 0 and be sequential. Type: {type.Name}, InvalidIndex: {item.Item1}");
                    }
                    expected++;
                }

                var foundConstructor = false;
                var ctors            = (type as INamedTypeSymbol)?.Constructors;
                foreach (var ctor in ctors)
                {
                    var isMatch = indexes.Select(x => x.Item2.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
                                  .SequenceEqual(ctor.Parameters.Select(x => x.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));
                    if (isMatch)
                    {
                        foundConstructor = true;
                    }
                }
                if (!foundConstructor && indexes.Count != 0)
                {
                    throw new Exception($"Struct needs full parameter constructor of index property types. Type: {type.Name}");
                }
            }

            var list = new List <ObjectSegmentType.PropertyTuple>();

            var definedIndexes = new HashSet <int>();

            foreach (var property in type.GetAllMembers())
            {
                var propSymbol  = property as IPropertySymbol;
                var fieldSymbol = property as IFieldSymbol;

                if ((propSymbol == null && fieldSymbol == null))
                {
                    continue;
                }

                if (property.DeclaredAccessibility != Accessibility.Public)
                {
                    continue;
                }

                var attributes = property.GetAttributes();
                if (attributes.FindAttributeShortName(IgnoreAttributeShortName) != null)
                {
                    continue;
                }

                if (!type.IsValueType)
                {
                    if (!property.IsVirtual)
                    {
                        throw new Exception($"Public property's accessor must be virtual. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                    }
                }

                var indexAttr = attributes.FindAttributeShortName(IndexAttributeShortName);
                if (indexAttr == null || indexAttr.ConstructorArguments.Length == 0)
                {
                    throw new Exception($"Public property must mark IndexAttribute or IgnoreFormatAttribute. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                }

                var index = indexAttr.ConstructorArguments[0];
                if (index.IsNull)
                {
                    continue; // null is normal compiler error.
                }

                if (!definedIndexes.Add((int)index.Value))
                {
                    throw new Exception($"IndexAttribute can not allow duplicate. {type.Name}.{property.Name}, Index:{index.Value} Location:{type.Locations[0]}");
                }

                if (!type.IsValueType)
                {
                    if (propSymbol == null)
                    {
                        throw new Exception($"Class does not allow that field marks IndexAttribute. {type.Name }{property.Name}");
                    }

                    if (propSymbol.GetMethod == null || propSymbol.SetMethod == null ||
                        propSymbol.GetMethod.DeclaredAccessibility == Accessibility.Private ||
                        propSymbol.SetMethod.DeclaredAccessibility == Accessibility.Private)
                    {
                        throw new Exception($"Public property's accessor must needs both public/protected get and set. {type.Name}.{property.Name}. Location:{type.Locations[0]}");
                    }
                }

                var memberType = (propSymbol != null) ? propSymbol.Type : fieldSymbol.Type;

                if (memberType.TypeKind == TypeKind.Array)
                {
                    var array = memberType as IArrayTypeSymbol;
                    var t     = array.ElementType;
                    if (t.SpecialType != SpecialType.System_Byte) // allows byte[]
                    {
                        throw new Exception($"Array does not support in ZeroFormatter(except byte[]) because Array have to deserialize all objects. You can use IList<T> instead of T[]. {type.Name}.{property.Name}.  Location:{type.Locations[0]}");
                    }
                }
                else
                {
                    var namedType = memberType as INamedTypeSymbol;
                    if (namedType != null) // if <T> is unnamed type, it can't analyze.
                    {
                        // Recursive
                        CollectObjectSegment(namedType);
                    }
                }

                var length = KnownFormatterSpec.GetLength(memberType);
                var prop   = new ObjectSegmentType.PropertyTuple
                {
                    Name           = property.Name,
                    Type           = memberType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                    Index          = (int)index.Value,
                    IsGetProtected = (propSymbol != null) ? propSymbol.GetMethod.DeclaredAccessibility == Accessibility.Protected : false,
                    IsSetProtected = (propSymbol != null) ? propSymbol.SetMethod.DeclaredAccessibility == Accessibility.Protected : false,
                    FixedSize      = length ?? 0,
                    IsProperty     = propSymbol != null,
                    IsCacheSegment = KnownFormatterSpec.CanAcceptCacheSegment(memberType),
                    IsFixedSize    = (length != null)
                };

                list.Add(prop);
            }

            var segment = new ObjectSegmentType
            {
                Name       = type.Name,
                FullName   = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                Namespace  = type.ContainingNamespace.IsGlobalNamespace ? null : type.ContainingNamespace.ToDisplayString(),
                LastIndex  = list.Select(x => x.Index).DefaultIfEmpty(0).Max(),
                Properties = list.OrderBy(x => x.Index).ToArray(),
            };

            if (type.IsValueType)
            {
                structContainer.Add(segment);
            }
            else
            {
                objectContainer.Add(segment);
            }
        }