private void GenerateDeserializeMethodBody(StringBuilder sb, DeserializeInvocation invocation)
        {
            DzTreeContext treeContext = new DzTreeContext();

            treeContext.IndentCSharp(+3);
            string ct = treeContext.CSharpIndent;

            List <MethodNode> nodes             = new List <MethodNode>();
            string            invocationTypeStr = invocation.TypeArg.ToString();
            DzJsonNode        dzTree            = BuildDzTree(invocation.TypeArg, "obj");

            if (dzTree is null)
            {
                nodes.Add(new CSharpLineNode($"{ct}obj = default({invocationTypeStr});"));
                nodes.Add(new CSharpLineNode($"{ct}// Type '{invocationTypeStr}' isn't marked as serializable!"));
            }
            else
            {
                nodes.Add(new CSharpLineNode($"{ct}ReadOnlySpan<char> json = content.AsSpan().TrimStart();"));
                nodes.Add(new CSharpLineNode($"{ct}if (json.IsEmpty)"));
                nodes.Add(new CSharpLineNode($"{ct}{{"));
                ct = treeContext.IndentCSharp(+1);
                nodes.Add(new CSharpLineNode($"{ct}obj = default({invocationTypeStr});"));
                nodes.Add(new CSharpLineNode($"{ct}return;"));
                ct = treeContext.IndentCSharp(-1);
                nodes.Add(new CSharpLineNode($"{ct}}}"));

                nodes.Add(new CSharpNode($"{ct}obj = "));
                nodes.AddRange(dzTree.GetNodes(treeContext));
                nodes.Add(new CSharpLineNode($";"));
            }


            //nodes.Add(new CSharpLineNode($"{ct}return new {invocationTypeStr}();"));

            foreach (CSharpNode node in nodes.OfType <CSharpNode>())
            {
                sb.Append(node.CSharpCode);
            }
        }
        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);
        }