Beispiel #1
0
        public static string GenerateSerializationPartialClass(
            this Compilation compilation,
            INamedTypeSymbol classSymbol,
            AttributeData serializableAttr,
            string?migrationPath,
            bool embedded,
            JsonSerializerOptions?jsonSerializerOptions,
            ImmutableArray <SerializableMetadata> migrations,
            ImmutableArray <ISymbol> fieldsAndProperties,
            ImmutableArray <INamedTypeSymbol> serializableTypes,
            ImmutableArray <INamedTypeSymbol> embeddedSerializableTypes
            )
        {
            var serializableFieldAttribute =
                compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_ATTRIBUTE);
            var serializableFieldAttrAttribute =
                compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_ATTR_ATTRIBUTE);
            var serializableInterface =
                compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_INTERFACE);
            var parentSerializableAttribute =
                compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_PARENT_ATTRIBUTE);
            var serializableFieldSaveFlagAttribute =
                compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_SAVE_FLAG_ATTRIBUTE);
            var serializableFieldDefaultAttribute =
                compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_DEFAULT_ATTRIBUTE);

            // If we have a parent that is or derives from ISerializable, then we are in override
            var isOverride = classSymbol.BaseType.ContainsInterface(serializableInterface);

            if (!(embedded || isOverride || classSymbol.ContainsInterface(serializableInterface)))
            {
                return(null);
            }

            var isRawSerializable = classSymbol.HasRawSerializableInterface(compilation, ImmutableArray <INamedTypeSymbol> .Empty);

            var version        = (int)serializableAttr.ConstructorArguments[0].Value !;
            var encodedVersion = (bool)serializableAttr.ConstructorArguments[1].Value !;

            // Let's find out if we need to do serialization flags
            var serializableFieldSaveFlags = new SortedDictionary <int, SerializableFieldSaveFlagMethods>();

            foreach (var m in classSymbol.GetMembers().OfType <IMethodSymbol>())
            {
                var getSaveFlagAttribute     = m.GetAttribute(serializableFieldSaveFlagAttribute);
                var getDefaultValueAttribute = m.GetAttribute(serializableFieldDefaultAttribute);

                if (getSaveFlagAttribute == null && getDefaultValueAttribute == null)
                {
                    continue;
                }

                var attrCtorArgs = getSaveFlagAttribute?.ConstructorArguments ?? getDefaultValueAttribute.ConstructorArguments;
                var order        = (int)attrCtorArgs[0].Value !;

                serializableFieldSaveFlags.TryGetValue(order, out var saveFlagMethods);

                serializableFieldSaveFlags[order] = new SerializableFieldSaveFlagMethods
                {
                    DetermineFieldShouldSerialize = getSaveFlagAttribute != null ? m : saveFlagMethods?.DetermineFieldShouldSerialize,
                    GetFieldDefaultValue          = getDefaultValueAttribute != null ? m : saveFlagMethods?.GetFieldDefaultValue
                };
            }

            var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
            var className     = classSymbol.Name;

            StringBuilder source = new StringBuilder();

            source.AppendLine("#pragma warning disable\n");
            source.GenerateNamespaceStart(namespaceName);

            var interfaces = !embedded || isRawSerializable
                ? Array.Empty <ITypeSymbol>()
                : new ITypeSymbol[]
            {
                compilation.GetTypeByMetadataName(SymbolMetadata.RAW_SERIALIZABLE_INTERFACE)
            };

            var indent = "    ";

            source.RecursiveGenerateClassStart(classSymbol, interfaces.ToImmutableArray(), ref indent);

            source.GenerateClassField(
                indent,
                Accessibility.Private,
                InstanceModifier.Const,
                "int",
                "_version",
                version.ToString()
                );
            source.AppendLine();

            var parentFieldOrProperty = embedded ? fieldsAndProperties.FirstOrDefault(
                fieldOrPropertySymbol => fieldOrPropertySymbol.GetAttributes()
                .FirstOrDefault(
                    attr =>
                    SymbolEqualityComparer.Default.Equals(attr.AttributeClass, parentSerializableAttribute)
                    ) != null
                ) : null;

            var serializablePropertySet = new SortedDictionary <SerializableProperty, ISymbol>(new SerializablePropertyComparer());

            foreach (var fieldOrPropertySymbol in fieldsAndProperties)
            {
                var allAttributes = fieldOrPropertySymbol.GetAttributes();

                var serializableFieldAttr = allAttributes
                                            .FirstOrDefault(
                    attr =>
                    SymbolEqualityComparer.Default.Equals(attr.AttributeClass, serializableFieldAttribute)
                    );

                if (serializableFieldAttr == null)
                {
                    continue;
                }

                foreach (var attr in allAttributes)
                {
                    if (!SymbolEqualityComparer.Default.Equals(attr.AttributeClass, serializableFieldAttrAttribute))
                    {
                        continue;
                    }

                    if (attr.AttributeClass == null)
                    {
                        continue;
                    }

                    var ctorArgs    = attr.ConstructorArguments;
                    var attrTypeArg = ctorArgs[0];

                    if (attrTypeArg.Kind == TypedConstantKind.Primitive && attrTypeArg.Value is string attrStr)
                    {
                        source.AppendLine($"{indent}{attrStr}");
                    }
                    else
                    {
                        var attrType = (ITypeSymbol)attrTypeArg.Value;
                        source.GenerateAttribute(indent, attrType?.Name, ctorArgs[1].Values);
                    }
                }

                var attrCtorArgs = serializableFieldAttr.ConstructorArguments;

                var order           = (int)attrCtorArgs[0].Value !;
                var getterAccessor  = Helpers.GetAccessibility(attrCtorArgs[1].Value?.ToString());
                var setterAccessor  = Helpers.GetAccessibility(attrCtorArgs[2].Value?.ToString());
                var virtualProperty = (bool)attrCtorArgs[3].Value !;

                if (fieldOrPropertySymbol is IFieldSymbol fieldSymbol)
                {
                    source.GenerateSerializableProperty(
                        compilation,
                        indent,
                        fieldSymbol,
                        getterAccessor,
                        setterAccessor,
                        virtualProperty,
                        parentFieldOrProperty
                        );
                    source.AppendLine();
                }

                serializableFieldSaveFlags.TryGetValue(order, out var serializableFieldSaveFlagMethods);

                var serializableProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty(
                    compilation,
                    fieldOrPropertySymbol,
                    order,
                    allAttributes,
                    serializableTypes,
                    embeddedSerializableTypes,
                    classSymbol,
                    serializableFieldSaveFlagMethods
                    );

                serializablePropertySet.Add(serializableProperty, fieldOrPropertySymbol);
            }

            var serializableFields     = serializablePropertySet.Keys.ToImmutableArray();
            var serializableProperties = serializablePropertySet.Select(
                kvp => kvp.Key with
            {
                Name = (kvp.Value as IFieldSymbol)?.GetPropertyName() ?? ((IPropertySymbol)kvp.Value).Name
            }