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); }
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); }