4 using System.Collections.Generic;
9 using SiliconStudio.AssemblyProcessor;
10 using SiliconStudio.Core.Serialization.Converters;
11 using SiliconStudio.Paradox.Data;
15 public partial class DataConverterGenerator
17 private Dictionary<TypeDefinition, DataTypeInfo> processedTypes =
new Dictionary<TypeDefinition, DataTypeInfo>();
18 private Dictionary<TypeDefinition, DataConverterInfo> processedConverterTypes =
new Dictionary<TypeDefinition, DataConverterInfo>();
19 private DataPropertyTypeVisitor dataPropertyTypeVisitor;
20 private AssemblyDefinition assembly;
22 private TypeDefinition listType;
23 private TypeDefinition dictionaryType;
25 private string currentNamespace = string.Empty;
29 this.assembly = assembly;
32 AssemblyDefinition mscorlibAssembly;
37 mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);
38 if (mscorlibAssembly == null)
39 throw new InvalidOperationException(
"Missing mscorlib.dll from assembly");
46 listType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(List<>).FullName);
47 dictionaryType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Dictionary<,>).FullName);
49 this.dataPropertyTypeVisitor =
new DataPropertyTypeVisitor(
this);
52 foreach (var type
in assembly.EnumerateTypes())
55 if(type.HasGenericParameters)
59 if (!(type.IsPublic || (type.IsNestedPublic && !type.HasGenericParameters)))
62 var dataInfo = this.GenerateDataTypeInfo(type);
65 var dataConverterInfo =
new DataConverterInfo
67 Generate = (dataInfo.Flags & DataTypeFlags.Generated) != 0,
69 Type = this.GetDataConverterType(type),
72 this.processedTypes.Add(type, dataInfo);
73 this.processedConverterTypes.Add(type, dataConverterInfo);
76 var additionalConverterAttribute = GetAdditionalDataAttribute(type);
77 if (additionalConverterAttribute != null)
79 var baseTypeArgument = GetAdditionalBaseType(type);
80 var dataConverterInfo =
new DataConverterInfo
82 DataInfo = this.GenerateDataTypeInfo(baseTypeArgument),
83 Type = this.GetDataConverterType(type),
86 foreach (var namedArgument
in additionalConverterAttribute.Properties)
88 switch (namedArgument.Name)
91 dataConverterInfo.Generate = (bool)namedArgument.Argument.Value;
96 this.processedConverterTypes.Add(type, dataConverterInfo);
101 private DataTypeInfo GenerateDataTypeInfo(TypeDefinition type)
103 DataTypeInfo existingDataTypeInfo;
104 if (this.processedTypes.TryGetValue(type, out existingDataTypeInfo))
105 return existingDataTypeInfo;
107 var
flags = GetDataTypeFlags(type);
108 if (flags == null || ((flags.Value & DataTypeFlags.NoDataType) != 0))
112 var properties =
new List<DataProperty>();
113 if ((flags.Value & DataTypeFlags.Generated) != 0)
115 properties.AddRange(this.EnumerateProperties(type));
118 return new DataTypeInfo
120 Type = this.GetDataType(type),
121 BaseType = (flags.Value & DataTypeFlags.Generated) != 0 ? this.GetDataType(type.BaseType.Resolve()) : null,
122 Properties = properties,
131 private void ChangeNamespace(
string newNamespace)
133 if (this.currentNamespace != newNamespace)
135 if (this.currentNamespace !=
string.Empty)
141 this.currentNamespace = newNamespace;
143 if (this.currentNamespace !=
string.Empty)
145 this.Write(
"namespace {0}\r\n", this.currentNamespace);
151 private TypeReference GetDataConverterType(TypeDefinition type)
154 return new TypeReference(type.Namespace +
".Data", type.Name +
"DataConverter", type.Module, type.Scope,
false);
157 private TypeReference GetDataType(TypeDefinition type)
159 var dataConverterAttribute = GetDataConverterAttribute(type);
160 if (dataConverterAttribute == null)
163 var flags = GetDataTypeFlags(type);
164 if (flags != null && ((flags.Value & DataTypeFlags.NoDataType) != 0))
167 var namedArgument = dataConverterAttribute.Properties.FirstOrDefault(x => x.Name ==
"DataTypeName");
168 var name = (namedArgument.Name != null) ? (
string)namedArgument.Argument.Value : type.Name +
"Data";
170 var lastDot = name.LastIndexOf(
'.');
171 var @
namespace = lastDot != -1 ? name.Substring(lastDot + 1) : type.Namespace +
".Data";
174 return new TypeReference(@
namespace, name, type.Module, type.Scope,
false);
177 private CustomAttribute GetAdditionalDataAttribute(TypeDefinition type)
184 private TypeDefinition GetAdditionalBaseType(TypeDefinition type)
188 var additionalConverterAttribute = GetAdditionalDataAttribute(type);
189 if (additionalConverterAttribute != null)
191 var baseTypeArgumentReference = (TypeReference)additionalConverterAttribute.ConstructorArguments[0].Value;
192 var baseTypeArgument = baseTypeArgumentReference.Resolve();
194 return baseTypeArgument;
199 private static CustomAttribute GetDataConverterAttribute(TypeDefinition type,
string name =
"SiliconStudio.Core.Serialization.Converters.DataConverterAttribute")
203 var dataConverterAttribute =
204 type.CustomAttributes.FirstOrDefault(
205 x => x.AttributeType.FullName == name);
206 if (dataConverterAttribute != null)
207 return dataConverterAttribute;
212 private static DataTypeFlags? GetDataTypeFlags(TypeDefinition type)
214 var dataConverterAttribute = GetDataConverterAttribute(type);
216 if (dataConverterAttribute == null)
219 var flags = DataTypeFlags.None;
221 foreach (var namedArgument
in dataConverterAttribute.Properties)
223 switch (namedArgument.Name)
226 if (!(
bool)namedArgument.Argument.Value)
227 flags |= DataTypeFlags.NoDataType;
230 if ((
bool)namedArgument.Argument.Value)
231 flags |= DataTypeFlags.Generated;
233 case "ContentReference":
234 if ((
bool)namedArgument.Argument.Value)
235 flags |= DataTypeFlags.ContentReference;
237 case "CustomConvertToData":
238 if ((
bool)namedArgument.Argument.Value)
239 flags |= DataTypeFlags.CustomConvertToData;
241 case "CustomConvertFromData":
242 if ((
bool)namedArgument.Argument.Value)
243 flags |= DataTypeFlags.CustomConvertFromData;
251 if (type.FullName == typeof(EntityModel.EntityComponent).FullName)
252 flags |= DataTypeFlags.EntityComponent;
255 type = type.BaseType != null ? type.BaseType.Resolve() : null;
264 foreach (var property
in type.Properties)
269 var dataProperty = CreateDataProperty(property.Name, property.PropertyType, property.SetMethod != null && (property.SetMethod.IsPublic || property.SetMethod.IsAssembly));
270 if (dataProperty != null)
271 yield
return dataProperty;
275 foreach (var field
in type.Fields)
280 var dataProperty = CreateDataProperty(field.Name, field.FieldType,
true);
281 if (dataProperty != null)
282 yield
return dataProperty;
286 private DataProperty CreateDataProperty(
string memberName, TypeReference memberType,
bool hasPublicSetAccessor)
288 var originalTypeReference = memberType;
289 var dataType = this.dataPropertyTypeVisitor.VisitDynamic(originalTypeReference);
291 var dataProperty =
new DataProperty
293 HasPublicSetAccessor = hasPublicSetAccessor,
294 OriginalType = originalTypeReference,
302 if (!dataProperty.HasPublicSetAccessor
303 && dataType.IsGenericInstance)
305 var dataTypeGenericInstance = (GenericInstanceType)dataType;
306 var elementType = dataType.GetElementType().Resolve();
308 foreach (var genericPattern
in new[]
310 new {GenericType = typeof(IList<>), InterfaceInitializerType = listType},
311 new {GenericType = typeof(
IDictionary<,>), InterfaceInitializerType = dictionaryType}
315 if (elementType.FullName == genericPattern.GenericType.FullName)
318 dataProperty.InitializerType =
319 dataTypeGenericInstance.ChangeGenericInstanceType(genericPattern.InterfaceInitializerType,
320 dataTypeGenericInstance.GenericArguments);
324 elementType.Interfaces.Any(
325 x => x.IsGenericInstance && x.GetElementType().FullName == genericPattern.GenericType.FullName))
328 if (elementType.Methods.Any(x => x.IsConstructor && x.Parameters.Count == 0))
330 dataProperty.InitializerType = dataType;
342 public bool HasPublicSetAccessor;
343 public TypeReference InitializerType;
344 public TypeReference OriginalType;
345 public TypeReference DataType;
351 private DataConverterGenerator dataConverterGenerator;
352 private TypeReference contentReferenceType;
353 private TypeReference entityComponentReferenceType;
355 public DataPropertyTypeVisitor(DataConverterGenerator dataConverterGenerator)
357 this.dataConverterGenerator = dataConverterGenerator;
358 var coreSerializationAssembly = dataConverterGenerator.assembly.MainModule.AssemblyResolver.Resolve(
"SiliconStudio.Core.Serialization");
359 this.contentReferenceType = dataConverterGenerator.assembly.MainModule.Import(coreSerializationAssembly.MainModule.GetTypeResolved(
"SiliconStudio.Core.Serialization.ContentReference`1"));
362 public TypeReference TryTransformToDataType(TypeReference type)
364 var resolvedType = type.Resolve();
365 var dataType = this.dataConverterGenerator.GetDataType(resolvedType);
366 if (dataType == null)
369 resolvedType = this.dataConverterGenerator.GetAdditionalBaseType(resolvedType);
370 if (resolvedType == null)
372 dataType = this.dataConverterGenerator.GetDataType(resolvedType);
375 var flags = GetDataTypeFlags(resolvedType).Value;
379 if ((flags & DataTypeFlags.EntityComponent) != 0)
381 if (entityComponentReferenceType == null)
383 var engineAssembly = dataConverterGenerator.assembly.MainModule.AssemblyResolver.Resolve(
"SiliconStudio.Paradox.Engine");
384 entityComponentReferenceType = dataConverterGenerator.assembly.MainModule.Import(engineAssembly.MainModule.GetTypeResolved(typeof(
EntityComponentReference<>).FullName));
388 var result =
new GenericInstanceType(entityComponentReferenceType);
389 result.GenericArguments.Add(type);
392 else if ((flags & DataTypeFlags.ContentReference) != 0)
395 var result =
new GenericInstanceType(this.contentReferenceType);
396 result.GenericArguments.Add(dataType);
403 public override TypeReference Visit(TypeReference type)
405 type = this.TryTransformToDataType(type);
407 return base.Visit(type);
413 public TypeReference
Type;
414 public TypeReference BaseType;
415 public DataTypeFlags
Flags;
416 public List<DataProperty> Properties;
419 class DataConverterInfo
421 public bool Generate;
422 public DataTypeInfo DataInfo;
423 public TypeReference
Type;
431 ContentReference = 2,
432 CustomConvertToData = 4,
433 CustomConvertFromData = 8,
435 EntityComponent = 32,
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
DataConverterGenerator(IAssemblyResolver assemblyResolver, AssemblyDefinition assembly)
Flags
Enumeration of the new Assimp's flags.
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.
Visit Cecil types recursively, and replace them if requested.