static void AddCollectionEquals(TypeDefinition type, MethodDefinition collectionEquals, PropertyDefinition property, TypeDefinition propType, Collection <Instruction> e, ParameterDefinition left, ParameterDefinition right) { e.If( cf => { cf.Add(Instruction.Create(type.GetLdArgForType(), right)); cf.Add(Instruction.Create(OpCodes.Ldnull)); cf.Add(Instruction.Create(OpCodes.Ceq)); }, t => t.Add(Instruction.Create(OpCodes.Ldc_I4_0)), es => { var getMethod = property.GetGetMethod(type); var getMethodImported = ReferenceFinder.ImportCustom(getMethod); es.Add(Instruction.Create(type.GetLdArgForType(), left)); es.Add(Instruction.Create(getMethodImported.GetCallForMethod(), getMethodImported)); if (propType.IsValueType && !property.PropertyType.IsArray) { es.Add(Instruction.Create(OpCodes.Box, propType)); } es.Add(Instruction.Create(type.GetLdArgForType(), right)); es.Add(Instruction.Create(getMethodImported.GetCallForMethod(), getMethodImported)); if (propType.IsValueType && !property.PropertyType.IsArray) { es.Add(Instruction.Create(OpCodes.Box, propType)); } es.Add(Instruction.Create(OpCodes.Call, collectionEquals)); }); }
static VariableDefinition AddNullableProperty(PropertyDefinition property, Collection <Instruction> ins, TypeDefinition type, VariableDefinition variable) { ins.If(c => { var nullablePropertyResolved = property.PropertyType.Resolve(); var nullablePropertyImported = ReferenceFinder.ImportCustom(property.PropertyType); ins.Add(Instruction.Create(OpCodes.Ldarg_0)); var getMethod = ReferenceFinder.ImportCustom(property.GetGetMethod(type)); c.Add(Instruction.Create(OpCodes.Call, getMethod)); variable = new VariableDefinition(getMethod.ReturnType); c.Add(Instruction.Create(OpCodes.Stloc, variable)); c.Add(Instruction.Create(OpCodes.Ldloca, variable)); var hasValuePropertyResolved = nullablePropertyResolved.Properties.First(x => x.Name == "HasValue").Resolve(); var hasMethod = ReferenceFinder.ImportCustom(hasValuePropertyResolved.GetGetMethod(nullablePropertyImported)); c.Add(Instruction.Create(OpCodes.Call, hasMethod)); }, t => { var nullableProperty = ReferenceFinder.ImportCustom(property.PropertyType); t.Add(Instruction.Create(OpCodes.Ldarg_0)); var imp = property.GetGetMethod(type); var imp2 = ReferenceFinder.ImportCustom(imp); t.Add(Instruction.Create(OpCodes.Call, imp2)); t.Add(Instruction.Create(OpCodes.Box, nullableProperty)); t.Add(Instruction.Create(OpCodes.Callvirt, ReferenceFinder.Object.GetHashcode)); }, e => e.Add(Instruction.Create(OpCodes.Ldc_I4_0))); return(variable); }
static void LoadVariable(PropertyDefinition property, Collection <Instruction> ins, TypeDefinition type) { var get = property.GetGetMethod(type); var imported = ReferenceFinder.ImportCustom(get); ins.Add(Instruction.Create(OpCodes.Ldarg_0)); ins.Add(Instruction.Create(OpCodes.Call, imported)); }
static void AddCustomLogicCall(TypeDefinition type, MethodBody body, Collection <Instruction> ins, MethodDefinition[] customLogic) { ins.IfNot( c => { var customMethod = ReferenceFinder.ImportCustom(customLogic[0]); var parameters = customMethod.Parameters; if (parameters.Count != 1) { throw new WeavingException( string.Format("Custom equals of type {0} have to have one parameter.", type.FullName)); } if (parameters[0].ParameterType.Resolve().FullName != type.FullName) { throw new WeavingException( string.Format("Custom equals of type {0} have to have one parameter of type {0}.", type.FullName)); } MethodReference selectedMethod; TypeReference resolverType; if (customMethod.DeclaringType.HasGenericParameters) { var genericInstanceType = type.GetGenericInstanceType(type); resolverType = ReferenceFinder.ImportCustom(genericInstanceType); var newRef = new MethodReference(customMethod.Name, customMethod.ReturnType) { DeclaringType = resolverType, HasThis = true, }; newRef.Parameters.Add(customMethod.Parameters[0].Name, resolverType); selectedMethod = newRef; } else { resolverType = type; selectedMethod = customMethod; } var imported = ReferenceFinder.ImportCustom(selectedMethod); if (!type.IsValueType) { ins.Add(Instruction.Create(OpCodes.Ldarg_0)); } else { var argVariable = body.Variables.Add("argVariable", resolverType); ins.Add(Instruction.Create(OpCodes.Ldarg_0)); ins.Add(Instruction.Create(OpCodes.Stloc, argVariable)); ins.Add(Instruction.Create(OpCodes.Ldloca, argVariable)); } ins.Add(Instruction.Create(OpCodes.Ldarg_1)); ins.Add(Instruction.Create(imported.GetCallForMethod(), imported)); }, AddReturnFalse); }
static VariableDefinition AddPropertyCode(PropertyDefinition property, bool isFirst, Collection <Instruction> ins, VariableDefinition resultVariable, MethodDefinition method, TypeDefinition type) { VariableDefinition variable = null; bool isCollection; var propType = ReferenceFinder.ImportCustom(property.PropertyType.GetGenericInstanceType(type)); if (property.PropertyType.IsGenericParameter) { isCollection = false; } else { isCollection = propType.Resolve().IsCollection() || property.PropertyType.IsArray; } AddMultiplicityByMagicNumber(isFirst, ins, resultVariable, isCollection); if (property.PropertyType.FullName.StartsWith("System.Nullable`1")) { variable = AddNullableProperty(property, ins, type, variable); } else if (property.PropertyType.IsValueType || property.PropertyType.IsGenericParameter) { LoadVariable(property, ins, type); if (property.PropertyType.FullName != "System.Int32") { ins.Add(Instruction.Create(OpCodes.Box, propType)); ins.Add(Instruction.Create(OpCodes.Callvirt, ReferenceFinder.Object.GetHashcode)); } } else { if (isCollection) { AddCollectionCode(property, isFirst, ins, resultVariable, method, type); } else { LoadVariable(property, ins, type); AddNormalCode(property, ins, type); } } if (!isFirst && !isCollection) { ins.Add(Instruction.Create(OpCodes.Xor)); } if (!isCollection) { ins.Add(Instruction.Create(OpCodes.Stloc, resultVariable)); } return(variable); }
static void GetEnumerator(Collection <Instruction> ins, VariableDefinition variable, PropertyDefinition property) { if (property.PropertyType.IsValueType) { var imported = ReferenceFinder.ImportCustom(property.PropertyType); ins.Add(Instruction.Create(OpCodes.Box, imported)); } ins.Add(Instruction.Create(OpCodes.Callvirt, ReferenceFinder.IEnumerable.GetEnumerator)); ins.Add(Instruction.Create(OpCodes.Stloc, variable)); }
static void AddSimpleValueCheck(Collection <Instruction> c, PropertyDefinition property, TypeDefinition type, ParameterDefinition left, ParameterDefinition right) { var getMethod = property.GetGetMethod(type); var getMethodImported = ReferenceFinder.ImportCustom(getMethod); c.Add(Instruction.Create(type.GetLdArgForType(), left)); c.Add(Instruction.Create(getMethodImported.GetCallForMethod(), getMethodImported)); c.Add(Instruction.Create(type.GetLdArgForType(), right)); c.Add(Instruction.Create(getMethodImported.GetCallForMethod(), getMethodImported)); c.Add(Instruction.Create(OpCodes.Ceq)); }
public static MethodDefinition Inject(TypeDefinition type, bool ignoreBaseClassProperties) { var methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; var method = new MethodDefinition("GetHashCode", methodAttributes, ReferenceFinder.Int32.TypeReference); method.CustomAttributes.MarkAsGeneratedCode(); var resultVariable = method.Body.Variables.Add("result", ReferenceFinder.Int32.TypeReference); var body = method.Body; body.InitLocals = true; var ins = body.Instructions; ins.Add(Instruction.Create(OpCodes.Ldc_I4_0)); ins.Add(Instruction.Create(OpCodes.Stloc, resultVariable)); var properties = ReferenceFinder.ImportCustom(type).Resolve().GetPropertiesWithoutIgnores(ignoreAttributeName); if (ignoreBaseClassProperties) { properties = properties.IgnoreBaseClassProperties(type); } if (properties.Length == 0) { AddResultInit(ins, resultVariable); } var isFirst = true; foreach (var property in properties) { var variable = AddPropertyCode(property, isFirst, ins, resultVariable, method, type); if (variable != null) { method.Body.Variables.Add(variable); } isFirst = false; } AddReturnCode(ins, resultVariable); body.OptimizeMacros(); type.Methods.AddOrReplace(method); return(method); }
public static MethodReference GetGetMethod(this PropertyDefinition property, TypeReference targetType) { MethodReference method = property.GetMethod; if (method.DeclaringType.HasGenericParameters) { var genericInstanceType = property.DeclaringType.GetGenericInstanceType(targetType); method = new MethodReference(method.Name, method.ReturnType.IsGenericParameter ? method.ReturnType : ReferenceFinder.ImportCustom(method.ReturnType)) { DeclaringType = ReferenceFinder.ImportCustom(genericInstanceType), HasThis = true }; } return(method); }
static void AddNormalCheck(TypeDefinition type, Collection <Instruction> c, PropertyDefinition property, ParameterDefinition left, ParameterDefinition right) { var genericInstance = new Lazy <TypeReference>(() => ReferenceFinder.ImportCustom(property.PropertyType.GetGenericInstanceType(type))); var getMethodImported = ReferenceFinder.ImportCustom(property.GetGetMethod(type)); c.Add(Instruction.Create(type.GetLdArgForType(), left)); c.Add(Instruction.Create(getMethodImported.GetCallForMethod(), getMethodImported)); if (property.PropertyType.IsValueType || property.PropertyType.IsGenericParameter) { c.Add(Instruction.Create(OpCodes.Box, genericInstance.Value)); } c.Add(Instruction.Create(type.GetLdArgForType(), right)); c.Add(Instruction.Create(getMethodImported.GetCallForMethod(), getMethodImported)); if (property.PropertyType.IsValueType || property.PropertyType.IsGenericParameter) { c.Add(Instruction.Create(OpCodes.Box, genericInstance.Value)); } c.Add(Instruction.Create(OpCodes.Call, ReferenceFinder.Object.StaticEquals)); }
static void AddCustomLogicCall(TypeDefinition type, MethodBody body, Collection <Instruction> ins, MethodDefinition customLogic) { var customMethod = ReferenceFinder.ImportCustom(customLogic); var parameters = customMethod.Parameters; if (parameters.Count != 0) { throw new WeavingException( string.Format("Custom GetHashCode of type {0} have to have empty parameter list.", type.FullName)); } if (customMethod.ReturnType.FullName != typeof(int).FullName) { throw new WeavingException( string.Format("Custom GetHashCode of type {0} have to return int.", type.FullName)); } MethodReference selectedMethod; TypeReference resolverType; if (customMethod.DeclaringType.HasGenericParameters) { var genericInstanceType = type.GetGenericInstanceType(type); resolverType = ReferenceFinder.ImportCustom(genericInstanceType); var newRef = new MethodReference(customMethod.Name, customMethod.ReturnType) { DeclaringType = resolverType, HasThis = true, }; selectedMethod = newRef; } else { selectedMethod = customMethod; } var imported = ReferenceFinder.ImportCustom(selectedMethod); ins.Add(Instruction.Create(OpCodes.Ldarg_0)); ins.Add(Instruction.Create(imported.GetCallForMethod(), imported)); }
public static MethodDefinition Inject(TypeDefinition type, bool ignoreBaseClassProperties) { var methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; var method = new MethodDefinition("GetHashCode", methodAttributes, ReferenceFinder.Int32.TypeReference); method.CustomAttributes.MarkAsGeneratedCode(); var resultVariable = method.Body.Variables.Add("result", ReferenceFinder.Int32.TypeReference); var body = method.Body; body.InitLocals = true; var ins = body.Instructions; ins.Add(Instruction.Create(OpCodes.Ldc_I4_0)); ins.Add(Instruction.Create(OpCodes.Stloc, resultVariable)); var properties = ReferenceFinder.ImportCustom(type).Resolve().GetPropertiesWithoutIgnores(ignoreAttributeName); if (ignoreBaseClassProperties) { properties = properties.IgnoreBaseClassProperties(type); } if (properties.Length == 0) { AddResultInit(ins, resultVariable); } var methods = type.GetMethods(); var customLogic = methods .Where(x => x.CustomAttributes.Any(y => y.AttributeType.Name == customAttribute)).ToArray(); if (customLogic.Length > 2) { throw new WeavingException("Only one custom method can be specified."); } var isFirst = true; foreach (var property in properties) { var variable = AddPropertyCode(property, isFirst, ins, resultVariable, method, type); if (variable != null) { method.Body.Variables.Add(variable); } isFirst = false; } if (customLogic.Length == 1) { ins.Add(Instruction.Create(OpCodes.Ldloc, resultVariable)); ins.Add(Instruction.Create(OpCodes.Ldc_I4, magicNumber)); ins.Add(Instruction.Create(OpCodes.Mul)); AddCustomLogicCall(type, body, ins, customLogic[0]); ins.Add(Instruction.Create(OpCodes.Xor)); ins.Add(Instruction.Create(OpCodes.Stloc, resultVariable)); } AddReturnCode(ins, resultVariable); body.OptimizeMacros(); type.Methods.AddOrReplace(method); return(method); }