Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ReferencedAssemblySerializerProcessor.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using Mono.Cecil;
7 using SiliconStudio.Core.Serialization.Serializers;
8 
9 namespace SiliconStudio.AssemblyProcessor.Serializers
10 {
11  /// <summary>
12  /// Fill <see cref="CecilSerializerContext.SerializableTypes"/> with serializable types handled by referenced assemblies.
13  /// </summary>
15  {
16  HashSet<AssemblyDefinition> processedAssemblies = new HashSet<AssemblyDefinition>();
17 
18  public void ProcessSerializers(CecilSerializerContext context)
19  {
20  ProcessDataSerializerGlobalAttributes(context, context.Assembly, true);
21  }
22 
23  private void ProcessDataSerializerGlobalAttributes(CecilSerializerContext context, AssemblyDefinition assembly, bool local)
24  {
25  // Already processed?
26  if (!processedAssemblies.Add(assembly))
27  return;
28 
29  // TODO: Add a flag for ComplexSerializer and transmit it properly (it needs different kind of analysis)
30 
31  // Let's recurse over referenced assemblies
32  foreach (var referencedAssemblyName in assembly.MainModule.AssemblyReferences)
33  {
34  // Avoid processing system assemblies
35  // TODO: Scan what is actually in framework folders
36  if (referencedAssemblyName.Name == "mscorlib" || referencedAssemblyName.Name.StartsWith("System")
37  || referencedAssemblyName.FullName.Contains("PublicKeyToken=31bf3856ad364e35")) // Signed with Microsoft public key (likely part of system libraries)
38  continue;
39 
40  var referencedAssembly = context.Assembly.MainModule.AssemblyResolver.Resolve(referencedAssemblyName);
41  ProcessDataSerializerGlobalAttributes(context, referencedAssembly, false);
42  }
43 
44  // Find DataSerializer attribute on assembly and/or types
45  foreach (var dataSerializerAttribute in
46  assembly.CustomAttributes.Concat(assembly.MainModule.Types.SelectMany(x => x.CustomAttributes)).Where(
47  x => x.AttributeType.FullName == "SiliconStudio.Core.Serialization.Serializers.DataSerializerGlobalAttribute")
48  .OrderBy(x => x.ConstructorArguments[0].Value != null ? -1 : 1)) // Order so that we first have the ones which don't require us to go through GenerateSerializer
49  {
50  var dataSerializerType = (TypeReference)dataSerializerAttribute.ConstructorArguments[0].Value;
51  var dataType = (TypeReference)dataSerializerAttribute.ConstructorArguments[1].Value;
52  var mode = (DataSerializerGenericMode)dataSerializerAttribute.ConstructorArguments[2].Value;
53  var inherited = (bool)dataSerializerAttribute.ConstructorArguments[3].Value;
54  var complexSerializer = (bool)dataSerializerAttribute.ConstructorArguments[4].Value;
55  var profile = dataSerializerAttribute.Properties.Where(x => x.Name == "Profile").Select(x => (string)x.Argument.Value).FirstOrDefault() ?? "Default";
56 
57  if (dataType == null)
58  {
59  if (mode == DataSerializerGenericMode.None)
60  dataType = FindSerializerDataType(dataSerializerType);
61  else
62  throw new InvalidOperationException("Can't deduce data serializer type for generic types.");
63  }
64 
65  CecilSerializerContext.SerializableTypeInfo serializableTypeInfo;
66 
67  if (dataSerializerType == null)
68  {
69  // TODO: We should avoid calling GenerateSerializer now just to have the dataSerializerType (we should do so only in a second step)
70  serializableTypeInfo = context.GenerateSerializer(dataType, profile: profile);
71  if (serializableTypeInfo == null)
72  throw new InvalidOperationException(string.Format("Can't find serializer for type {0}", dataType));
73  serializableTypeInfo.Local = local;
74  serializableTypeInfo.ExistingLocal = local;
75  dataSerializerType = serializableTypeInfo.SerializerType;
76  }
77  else
78  {
79  // Add it to list of serializable types
80  serializableTypeInfo = new CecilSerializerContext.SerializableTypeInfo(dataSerializerType, local, mode) { ExistingLocal = local, Inherited = inherited, ComplexSerializer = complexSerializer };
81  context.AddSerializableType(dataType, serializableTypeInfo, profile);
82  }
83  }
84  }
85 
86  public static TypeReference FindSerializerDataType(TypeReference dataSerializerType)
87  {
88  // Find "DataSerializer<T>" base and its dataType (T)
89  TypeReference dataType = null;
90  var dataSerializerTypeCurrent = dataSerializerType;
91  while (dataSerializerTypeCurrent != null)
92  {
93  var genericInstanceType = dataSerializerTypeCurrent as GenericInstanceType;
94  if (genericInstanceType != null)
95  {
96  if (genericInstanceType.ElementType.FullName == "SiliconStudio.Core.Serialization.DataSerializer`1")
97  {
98  dataType = genericInstanceType.GenericArguments[0];
99  break;
100  }
101  }
102 
103  var baseType = ResolveGenericsVisitor.Process(dataSerializerTypeCurrent, dataSerializerTypeCurrent.Resolve().BaseType);
104 
105  dataSerializerTypeCurrent = baseType;
106  }
107 
108  if (dataType == null)
109  throw new InvalidOperationException(string.Format("Could not determine data type for {0}.", dataSerializerType));
110  return dataType;
111  }
112  }
113 }
DataSerializerGenericMode
Defines what generic parameters to pass to the serializer.
Gives the required generic serializer for a given type. This is useful for generation of serializatio...
void ProcessSerializers(CecilSerializerContext context)
Process serializers for given assembly context.
Fill CecilSerializerContext.SerializableTypes with serializable types handled by referenced assemblie...