static void AddStaticEqualsCall(TypeDefinition type, Collection<Instruction> ins) { if (type.IsValueType) { var resolved = type.GetGenericInstanceType(type); ins.Add(Instruction.Create(OpCodes.Ldarg_0)); ins.Add(Instruction.Create(OpCodes.Box, resolved)); ins.Add(Instruction.Create(OpCodes.Ldarg_1)); ins.Add(Instruction.Create(OpCodes.Box, resolved)); } else { ins.Add(Instruction.Create(OpCodes.Ldarg_0)); ins.Add(Instruction.Create(OpCodes.Ldarg_1)); } ins.Add(Instruction.Create(OpCodes.Call, ReferenceFinder.Object.StaticEquals)); }
static MethodDefinition AddOperator(TypeDefinition type, bool isEquality) { var methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static; var method = new MethodDefinition(isEquality ? "op_Equality" : "op_Inequality", methodAttributes, ReferenceFinder.Boolean.TypeReference); method.CustomAttributes.MarkAsGeneratedCode(); var parameterType = type.GetGenericInstanceType(type); method.Parameters.Add("left", parameterType); method.Parameters.Add("right", parameterType); var body = method.Body; var ins = body.Instructions; AddStaticEqualsCall(type, ins); AddReturnValue(isEquality, ins); body.OptimizeMacros(); type.Methods.AddOrReplace(method); return method; }
static void AddInternalEqualsCall(TypeDefinition type, TypeReference typeRef, MethodReference newEquals, Collection<Instruction> t, VariableDefinition result) { t.Add(Instruction.Create(OpCodes.Ldarg_0)); if (type.IsValueType) { var resolvedType = type.GetGenericInstanceType(type); t.Add(Instruction.Create(OpCodes.Ldobj, resolvedType)); } t.Add(Instruction.Create(OpCodes.Ldarg_1)); if (type.IsValueType) { t.Add(Instruction.Create(OpCodes.Unbox_Any, typeRef)); } else { t.Add(Instruction.Create(OpCodes.Castclass, typeRef)); } t.Add(Instruction.Create(OpCodes.Call, newEquals)); t.Add(Instruction.Create(OpCodes.Stloc, result)); }
static void AddExactlyTheSameTypeAsThis(TypeDefinition type, Collection<Instruction> c) { c.Add(Instruction.Create(OpCodes.Ldarg_0)); if (type.IsValueType) { var resolved = type.GetGenericInstanceType(type); c.Add(Instruction.Create(OpCodes.Ldobj, resolved)); c.Add(Instruction.Create(OpCodes.Box, resolved)); } c.Add(Instruction.Create(OpCodes.Call, ReferenceFinder.Object.GetType)); c.Add(Instruction.Create(OpCodes.Ldarg_1)); c.Add(Instruction.Create(OpCodes.Callvirt, ReferenceFinder.Object.GetType)); c.Add(Instruction.Create(OpCodes.Ceq)); }
static void AddExactlyOfType(TypeDefinition type, TypeReference typeRef, Collection<Instruction> c) { c.Add(Instruction.Create(OpCodes.Ldarg_0)); if (type.IsValueType) { var resolved = type.GetGenericInstanceType(type); c.Add(Instruction.Create(OpCodes.Ldobj, resolved)); c.Add(Instruction.Create(OpCodes.Box, resolved)); } c.Add(Instruction.Create(OpCodes.Call, ReferenceFinder.Object.GetType)); c.Add(Instruction.Create(OpCodes.Ldtoken, typeRef)); c.Add(Instruction.Create(OpCodes.Call, ReferenceFinder.Type.GetTypeFromHandle)); c.Add(Instruction.Create(OpCodes.Ceq)); }
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 void AddCheckEqualsReference(TypeDefinition type, Collection<Instruction> ins, bool skipBoxingSecond) { var resolvedType = type.IsValueType ? type.GetGenericInstanceType(type) : null; ins.If( c => { c.Add(Instruction.Create(OpCodes.Ldnull)); c.Add(Instruction.Create(OpCodes.Ldarg_1)); if (type.IsValueType && !skipBoxingSecond) { c.Add(Instruction.Create(OpCodes.Box, resolvedType)); } c.Add(Instruction.Create(OpCodes.Call, ReferenceFinder.Object.ReferenceEquals)); }, AddReturnFalse); ins.If( c => { c.Add(Instruction.Create(OpCodes.Ldarg_0)); if (type.IsValueType) { c.Add(Instruction.Create(OpCodes.Ldobj, resolvedType)); c.Add(Instruction.Create(OpCodes.Box, resolvedType)); } c.Add(Instruction.Create(OpCodes.Ldarg_1)); if (type.IsValueType && !skipBoxingSecond) { c.Add(Instruction.Create(OpCodes.Box, resolvedType)); } c.Add(Instruction.Create(OpCodes.Call, ReferenceFinder.Object.ReferenceEquals)); }, AddReturnTrue); }