private DzJsonNode BuildDzTree(ITypeSymbol symbol, string csObj)
        {
            if (symbol.Kind != SymbolKind.NamedType)
            {
                return(null);
            }

            // primitive types
            switch (symbol.SpecialType)
            {
            case SpecialType.System_Int32:
                _deserializeIntRequired = true;
                return(new DzCallNode("DeserializeInt(ref content, ref json)"));

            case SpecialType.System_String:
                _deserializeStringRequired = true;
                return(new DzCallNode("DeserializeString(ref content, ref json)"));

            default:
                break;
            }

            // if is serializable class
            string            invocationTypeStr = symbol.ToString();
            SerializableClass foundClass        = _knownClasses.FirstOrDefault(c => c.Type.ToString().Equals(invocationTypeStr));

            if (foundClass != null)
            {
                if (!_requiredTypeDeserializers.ContainsKey(invocationTypeStr))
                {
                    DzObjectNode objectNode = new DzObjectNode(invocationTypeStr);
                    foreach (SerializableProperty sp in foundClass.Properties)
                    {
                        DzJsonNode value = BuildDzTree(sp.Type, $"obj.{sp.Name}");
                        if (value is DzExpressionNode expr)
                        {
                            DzAssignmentNode assignment = new DzAssignmentNode($"obj.{sp.Name}", expr);
                            objectNode.Properties.Add((sp.Name, assignment));
                        }
                        else
                        {
                            throw new Exception("Expected expression for object property assignment!");
                        }
                    }

                    _requiredTypeDeserializers.Add(invocationTypeStr, objectNode);
                }
                string validName = invocationTypeStr.Replace(".", "_");
                return(new DzCallNode($"Deserialize_{validName}(ref content, ref json)"));
            }

            // list, dictionnary, ...

            // fallback on list
            INamedTypeSymbol enumerable = null;

            if (symbol.MetadataName.Equals("IList`1"))
            {
                enumerable = symbol as INamedTypeSymbol;
            }
            else
            {
                enumerable = symbol.AllInterfaces.FirstOrDefault(i => i.MetadataName.Equals("IList`1"));
            }
            if (enumerable != null)
            {
                ITypeSymbol listType = enumerable.TypeArguments.First();

                DzListNode listNode = new DzListNode(listType.ToString());
                DzJsonNode value    = BuildDzTree(listType, $"obj");
                if (value is DzExpressionNode expr)
                {
                    listNode.Property = new DzAppendListNode($"obj", expr);
                }
                else
                {
                    throw new Exception("Expected expression for object list append!");
                }

                _requiredTypeDeserializers.Add(invocationTypeStr, listNode);

                string objectTypeStrValid = listNode.Type.Replace(".", "_").Replace("<", "_").Replace(">", "");
                return(new DzCallNode($"DeserializeList_{objectTypeStrValid}(ref content, ref json)"));
            }

            // fallback on enumerables?

            // If reached here, type isn't supported
            _context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.ClassNotSerializable, symbol.Locations.First(), invocationTypeStr));
            return(null);
        }
        private JsonNode BuildTree(ITypeSymbol symbol, string csObj)
        {
            if (symbol.Kind != SymbolKind.NamedType)
            {
                return(null);
            }

            // primitive types
            switch (symbol.SpecialType)
            {
            case SpecialType.System_Int32:
                return(new NumericNode(csObj));

            case SpecialType.System_String:
                return(new StringNode(csObj));

            default:
                break;
            }

            // if is serializable class
            string            invocationTypeStr = symbol.ToString();
            SerializableClass foundClass        = _knownClasses.FirstOrDefault(c => c.Type.ToString().Equals(invocationTypeStr));

            if (foundClass != null)
            {
                ObjectNode objectNode = new ObjectNode(csObj);
                objectNode.CanBeNull = foundClass.CanBeNull;
                foreach (SerializableProperty sp in foundClass.Properties)
                {
                    JsonNode value = BuildTree(sp.Type, $"{csObj}.{sp.Name}");
                    if (value is NullableNode nn)
                    {
                        nn.CanBeNull = sp.CanBeNull;
                    }
                    if (value is ListNode ln && ln.ElementType is NullableNode lnn)
                    {
                        lnn.CanBeNull = lnn.CanBeNull && sp.ArrayItemCanBeNull;
                    }
                    objectNode.Properties.Add((sp.Name, value));
                }
                return(objectNode);
            }

            // list, dictionnary, ...

            // fallback on list
            INamedTypeSymbol enumerable = null;

            if (symbol.MetadataName.Equals("IList`1"))
            {
                enumerable = symbol as INamedTypeSymbol;
            }
            else
            {
                enumerable = symbol.AllInterfaces.FirstOrDefault(i => i.MetadataName.Equals("IList`1"));
            }
            if (enumerable != null)
            {
                ITypeSymbol listType = enumerable.TypeArguments.First();

                ListNode listNode = new ListNode(csObj);
                listNode.ElementType = BuildTree(listType, $"{csObj}[i]");
                return(listNode);
            }

            // fallback on enumerables?

            // If reached here, type isn't supported
            _context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.ClassNotSerializable, symbol.Locations.First(), invocationTypeStr));
            return(null);
        }
Пример #3
0
        private void VisitClassOrStructDeclaration(TypeDeclarationSyntax node)
        {
            bool isSerializable = false;

            // Start by a quick check
            foreach (AttributeListSyntax attrList in node.AttributeLists)
            {
                foreach (AttributeSyntax attr in attrList.Attributes)
                {
                    string name = attr.Name.ToString();
                    if (name.Contains("Serialize"))
                    {
                        isSerializable = true;
                        break;
                    }
                }
                if (isSerializable)
                {
                    break;
                }
            }

            if (!isSerializable)
            {
                return;
            }

            INamedTypeSymbol type = _semanticModel.GetDeclaredSymbol(node);

            // Can't do Proper check if we generate the attribute
            //isSerializable = type.GetAttributes().Any(a => a.AttributeClass.ToString().Equals("MetaJson.SerializeAttribute"));
            //if (!isSerializable)
            //{
            //    base.VisitClassDeclaration(node);
            //    return;
            //}


            SerializableClass sc = new SerializableClass()
            {
                Name        = node.Identifier.ValueText,
                Declaration = node,
                Type        = type,
                CanBeNull   = !type.IsValueType && !type.GetAttributes().Any(a => a.AttributeClass.ToString().Contains("NotNull"))
            };

            ImmutableArray <ISymbol> members = type.GetMembers();


            foreach (ISymbol serializableProperty in type.GetMembers())
            {
                // serializableProperty.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() as PropertyDeclarationSyntax,

                ITypeSymbol typeSymbol = null;
                if (serializableProperty is IPropertySymbol ps)
                {
                    typeSymbol = ps.Type;
                }
                else if (serializableProperty is IFieldSymbol fs)
                {
                    typeSymbol = fs.Type;
                }
                else
                {
                    continue;
                }

                ImmutableArray <AttributeData> attributes = serializableProperty.GetAttributes();
                if (!attributes.Any(a => a.AttributeClass.ToString().Contains("Serialize")))
                {
                    continue;
                }

                SerializableProperty sp = new SerializableProperty()
                {
                    Name               = serializableProperty.Name,
                    Type               = typeSymbol,
                    CanBeNull          = !typeSymbol.IsValueType && !attributes.Any(a => a.AttributeClass.ToString().Contains("NotNull")),
                    ArrayItemCanBeNull = !attributes.Any(a => a.AttributeClass.ToString().Contains("ArrayItemNotNull"))
                };

                sc.Properties.Add(sp);
            }

            SerializableClasses.Add(sc);
        }