5 using System.Reflection;
9 using Mono.Cecil.Rocks;
13 namespace SiliconStudio.AssemblyProcessor
21 private TypeReference voidType, stringType, objectType;
26 typeof(PdbReader).ToString();
32 var propertyChangedField = typeDefinition.Fields.FirstOrDefault(x => x.FieldType.FullName == typeof(System.ComponentModel.PropertyChangedEventHandler).FullName && x.Name ==
"PropertyChanged");
33 if (propertyChangedField != null)
34 return propertyChangedField;
45 var method = typeDefinition.Methods.FirstOrDefault(x => x.Name ==
"GetPropertyChanged");
47 return assembly.MainModule.Import(method);
49 if (typeDefinition.BaseType != null)
50 return GetGetPropertyChangedMethod(assembly, typeDefinition.BaseType.Resolve());
57 var methodReference = GetGetPropertyChangedMethod(assembly, typeDefinition);
58 if (methodReference != null)
59 return methodReference;
61 var method =
new MethodDefinition(
"GetPropertyChanged",
MethodAttributes.Family, propertyChangedField.FieldType);
63 var bodyInstructions = method.Body.Instructions;
66 bodyInstructions.Add(Instruction.Create(OpCodes.Ldarg_0));
67 bodyInstructions.Add(Instruction.Create(OpCodes.Ldfld, propertyChangedField));
68 bodyInstructions.Add(Instruction.Create(OpCodes.Ret));
70 typeDefinition.Methods.Add(method);
77 var assembly = context.Assembly;
78 var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);
79 if (mscorlibAssembly == null)
80 throw new InvalidOperationException(
"Missing mscorlib.dll from assembly");
83 voidType = assembly.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved(typeof(
void).FullName));
84 stringType = assembly.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved(typeof(
string).FullName));
85 objectType = assembly.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved(typeof(
object).FullName));
86 var propertyInfoType = assembly.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved(typeof(PropertyInfo).FullName));
88 var typeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(
Type).FullName);
91 TypeDefinition propertyChangedExtendedEventArgsType;
93 AssemblyDefinition siliconStudioCoreAssembly = null;
96 siliconStudioCoreAssembly = assembly.Name.Name ==
"SiliconStudio.Core"
98 : context.AssemblyResolver.Resolve(
"SiliconStudio.Core");
106 propertyChangedExtendedEventArgsType = siliconStudioCoreAssembly.MainModule.GetTypes().First(x => x.Name ==
"PropertyChangedExtendedEventArgs").Resolve();
108 var typeTokenInfoEx = mscorlibAssembly.MainModule.GetType(
"System.Reflection.TypeInfo").Resolve();
109 var getPropertyMethod = typeTokenInfoEx.Methods.First(x => x.Name ==
"GetDeclaredProperty" && x.Parameters.Count == 1);
110 var getTypeFromHandleMethod = typeType.Methods.First(x => x.Name ==
"GetTypeFromHandle");
111 var getTokenInfoExMethod = mscorlibAssembly.MainModule.GetType(
"System.Reflection.IntrospectionExtensions").Resolve().Methods.First(x => x.Name ==
"GetTypeInfo");
113 var propertyChangedExtendedEventArgsConstructor = assembly.MainModule.Import(propertyChangedExtendedEventArgsType.Methods.First(x => x.IsConstructor));
115 bool modified =
false;
117 foreach (var type
in assembly.MainModule.GetTypes())
119 MethodReference getPropertyChangedMethod = null;
121 getPropertyChangedMethod = GetGetPropertyChangedMethod(assembly, type);
126 var propertyChangedField = GetPropertyChangedField(type);
128 if (getPropertyChangedMethod == null && propertyChangedField == null)
131 TypeReference propertyChangedFieldType;
133 if (getPropertyChangedMethod == null)
136 getPropertyChangedMethod = GetOrCreateGetPropertyChangedMethod(assembly, type, propertyChangedField);
139 if (propertyChangedField != null)
141 propertyChangedField = assembly.MainModule.Import(propertyChangedField);
142 propertyChangedFieldType = propertyChangedField.FieldType;
146 propertyChangedFieldType = getPropertyChangedMethod.ReturnType;
150 if (getPropertyChangedMethod.DeclaringType.HasGenericParameters)
151 getPropertyChangedMethod = getPropertyChangedMethod.MakeGeneric(getPropertyChangedMethod.DeclaringType.GenericParameters.ToArray());
153 var propertyChangedInvoke = assembly.MainModule.Import(propertyChangedFieldType.Resolve().Methods.First(x => x.Name ==
"Invoke"));
155 foreach (var property
in type.Properties)
157 if (property.SetMethod == null || !property.HasThis)
160 MethodReference propertyGetMethod = property.GetMethod;
163 var methodDefinition = propertyGetMethod.Resolve();
164 if ((methodDefinition.Attributes &
MethodAttributes.Public) != MethodAttributes.Public)
170 if (propertyGetMethod.DeclaringType.HasGenericParameters)
171 propertyGetMethod = propertyGetMethod.MakeGeneric(propertyGetMethod.DeclaringType.GenericParameters.ToArray());
180 type.Fields.Add((FieldDefinition)staticField);
183 if (staticField.DeclaringType.HasGenericParameters)
184 staticField = staticField.MakeGeneric(staticField.DeclaringType.GenericParameters.ToArray());
188 var staticConstructor = type.GetStaticConstructor();
189 if (staticConstructor == null)
191 staticConstructor =
new MethodDefinition(
".cctor",
194 staticConstructor.Body.GetILProcessor().Append(Instruction.Create(OpCodes.Ret));
196 type.Methods.Add(staticConstructor);
200 VariableReference localTokenEx = null;
201 int localTokenExIndex = 0;
202 for (
int i = 0; i < staticConstructor.Body.Variables.Count; i++)
204 var localVar = staticConstructor.Body.Variables[i];
205 if (localVar.VariableType.FullName == typeTokenInfoEx.FullName)
207 localTokenEx = localVar;
208 localTokenExIndex = i;
213 if (localTokenEx == null)
215 localTokenEx =
new VariableDefinition(assembly.MainModule.Import(typeTokenInfoEx));
216 staticConstructor.Body.Variables.Add((VariableDefinition)localTokenEx);
217 localTokenExIndex = staticConstructor.Body.Variables.Count - 1;
220 var ilProcessor = staticConstructor.Body.GetILProcessor();
221 var returnInstruction = staticConstructor.Body.Instructions.Last();
223 var newReturnInstruction = Instruction.Create(returnInstruction.OpCode);
224 newReturnInstruction.Operand = returnInstruction.Operand;
226 returnInstruction.OpCode = OpCodes.Nop;
227 returnInstruction.Operand = null;
230 ilProcessor.Append(Instruction.Create(OpCodes.Ldtoken, type));
231 ilProcessor.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.Import(getTypeFromHandleMethod)));
232 ilProcessor.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.Import(getTokenInfoExMethod)));
233 ilProcessor.Append(LocationToStloc(ilProcessor, localTokenExIndex));
234 ilProcessor.Append(ilProcessor.Create(OpCodes.Ldloca_S, (byte)localTokenExIndex));
235 ilProcessor.Append(Instruction.Create(OpCodes.Ldstr, property.Name));
236 ilProcessor.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.Import(getPropertyMethod)));
237 ilProcessor.Append(Instruction.Create(OpCodes.Stsfld, staticField));
239 ilProcessor.Append(newReturnInstruction);
243 var ilProcessor = property.SetMethod.Body.GetILProcessor();
244 var returnInstruction = property.SetMethod.Body.Instructions.Last();
246 var firstInstruction = property.SetMethod.Body.Instructions[0];
248 if (property.SetMethod.Body.Instructions[0].OpCode != OpCodes.Nop)
249 ilProcessor.InsertBefore(property.SetMethod.Body.Instructions[0], Instruction.Create(OpCodes.Nop));
251 var newReturnInstruction = Instruction.Create(returnInstruction.OpCode);
252 newReturnInstruction.Operand = returnInstruction.Operand;
254 returnInstruction.OpCode = OpCodes.Nop;
255 returnInstruction.Operand = null;
257 var propertyChangedVariable =
new VariableDefinition(
"propertyChanged", assembly.MainModule.Import(propertyChangedFieldType));
258 property.SetMethod.Body.Variables.Add(propertyChangedVariable);
260 var oldValueVariable =
new VariableDefinition(
"oldValue", objectType);
261 property.SetMethod.Body.Variables.Add(oldValueVariable);
263 Instruction jump1, jump2;
268 property.SetMethod.Body.SimplifyMacros();
269 ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Ldarg_0));
270 ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Call, getPropertyChangedMethod));
271 ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Stloc, propertyChangedVariable));
272 ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Ldloc, propertyChangedVariable));
273 ilProcessor.InsertBefore(firstInstruction, jump1 = Instruction.Create(OpCodes.Brtrue, Instruction.Create(OpCodes.Nop)));
274 ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Ldnull));
275 ilProcessor.InsertBefore(firstInstruction, jump2 = Instruction.Create(OpCodes.Br, Instruction.Create(OpCodes.Nop)));
276 ilProcessor.InsertBefore(firstInstruction, (Instruction)(jump1.Operand = Instruction.Create(OpCodes.Ldarg_0)));
277 ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Call, propertyGetMethod));
278 if (property.PropertyType.IsValueType)
279 ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Box, property.PropertyType));
280 ilProcessor.InsertBefore(firstInstruction, (Instruction)(jump2.Operand = Instruction.Create(OpCodes.Nop)));
281 ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Stloc, oldValueVariable));
286 ilProcessor.Append(Instruction.Create(OpCodes.Ldloc, propertyChangedVariable));
287 ilProcessor.Append(Instruction.Create(OpCodes.Ldnull));
288 ilProcessor.Append(Instruction.Create(OpCodes.Ceq));
289 ilProcessor.Append(Instruction.Create(OpCodes.Brtrue, newReturnInstruction));
290 ilProcessor.Append(Instruction.Create(OpCodes.Ldloc, propertyChangedVariable));
291 ilProcessor.Append(Instruction.Create(OpCodes.Ldarg_0));
292 ilProcessor.Append(Instruction.Create(OpCodes.Ldsfld, staticField));
293 ilProcessor.Append(Instruction.Create(OpCodes.Ldloc, oldValueVariable));
294 ilProcessor.Append(Instruction.Create(OpCodes.Ldarg_0));
295 ilProcessor.Append(Instruction.Create(OpCodes.Call, propertyGetMethod));
296 if (property.PropertyType.IsValueType)
297 ilProcessor.Append(Instruction.Create(OpCodes.Box, property.PropertyType));
298 ilProcessor.Append(Instruction.Create(OpCodes.Newobj, propertyChangedExtendedEventArgsConstructor));
299 ilProcessor.Append(Instruction.Create(OpCodes.Callvirt, propertyChangedInvoke));
300 ilProcessor.Append(Instruction.Create(OpCodes.Nop));
301 ilProcessor.Append(newReturnInstruction);
302 property.SetMethod.Body.OptimizeMacros();
311 private static Instruction LocationToStloc(ILProcessor ilProcessor,
int index)
313 Instruction stlocFixed;
317 stlocFixed = ilProcessor.Create(OpCodes.Stloc_0);
320 stlocFixed = ilProcessor.Create(OpCodes.Stloc_1);
323 stlocFixed = ilProcessor.Create(OpCodes.Stloc_2);
326 stlocFixed = ilProcessor.Create(OpCodes.Stloc_3);
329 stlocFixed = ilProcessor.Create(OpCodes.Stloc, index);
336 private static Instruction LocationToLdLoc(ILProcessor ilProcessor,
int index)
338 Instruction ldlocFixed;
342 ldlocFixed = ilProcessor.Create(OpCodes.Ldloc_0);
345 ldlocFixed = ilProcessor.Create(OpCodes.Ldloc_1);
348 ldlocFixed = ilProcessor.Create(OpCodes.Ldloc_2);
351 ldlocFixed = ilProcessor.Create(OpCodes.Ldloc_3);
354 ldlocFixed = ilProcessor.Create(OpCodes.Ldloc, index);
FieldReference GetPropertyChangedField(TypeDefinition typeDefinition)
Mono.Cecil.MethodAttributes MethodAttributes
Mono.Cecil.FieldAttributes FieldAttributes
bool Process(AssemblyProcessorContext context)
MethodReference GetGetPropertyChangedMethod(AssemblyDefinition assembly, TypeDefinition typeDefinition)
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}.
This class is no longer used now. TODO: Check if we need to keep this around
Mono.Cecil.MethodAttributes MethodAttributes
MethodReference GetOrCreateGetPropertyChangedMethod(AssemblyDefinition assembly, TypeDefinition typeDefinition, FieldReference propertyChangedField)