static bool IsGetterSetterPair(object getterOperand, object setterOperand) { MethodReference getter = getterOperand as MethodReference; MethodReference setter = setterOperand as MethodReference; if (getter == null || setter == null) { return(false); } if (!TypeAnalysis.IsSameType(getter.DeclaringType, setter.DeclaringType)) { return(false); } MethodDefinition getterDef = getter.Resolve(); MethodDefinition setterDef = setter.Resolve(); if (getterDef == null || setterDef == null) { return(false); } foreach (PropertyDefinition prop in getterDef.DeclaringType.Properties) { if (prop.GetMethod == getterDef) { return(prop.SetMethod == setterDef); } } return(false); }
ILExpression IntroducePostIncrementForInstanceFields(ILExpression expr) { // stfld(field, ldloc(instance), add(stloc(helperVar, ldfld(field, ldloc(instance))), ldc.i4(1))) // -> stloc(helperVar, postincrement(1, ldflda(field, ldloc(instance)))) // Also works for array elements and pointers: // stelem.any(T, ldloc(instance), ldloc(pos), add(stloc(helperVar, ldelem.any(T, ldloc(instance), ldloc(pos))), ldc.i4(1))) // -> stloc(helperVar, postincrement(1, ldelema(ldloc(instance), ldloc(pos)))) // stobj(T, ldloc(ptr), add(stloc(helperVar, ldobj(T, ldloc(ptr)), ldc.i4(1)))) // -> stloc(helperVar, postIncrement(1, ldloc(ptr))) // callsetter(set_P, ldloc(instance), add(stloc(helperVar, callgetter(get_P, ldloc(instance))), ldc.i4(1))) // -> stloc(helperVar, postIncrement(1, propertyaddress. callgetter(get_P, ldloc(instance)))) if (!(expr.Code == ILCode.Stfld || expr.Code.IsStoreToArray() || expr.Code == ILCode.Stobj || expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter)) { return(null); } // Test that all arguments except the last are ldloc (1 arg for fields and pointers, 2 args for arrays) for (int i = 0; i < expr.Arguments.Count - 1; i++) { if (expr.Arguments[i].Code != ILCode.Ldloc) { return(null); } } ILExpression addExpr = expr.Arguments[expr.Arguments.Count - 1]; int incrementAmount; ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount); ILVariable helperVar; ILExpression initialValue; if (!(incrementAmount != 0 && addExpr.Arguments[0].Match(ILCode.Stloc, out helperVar, out initialValue))) { return(null); } if (expr.Code == ILCode.Stfld) { if (initialValue.Code != ILCode.Ldfld) { return(null); } // There might be two different FieldReference instances, so we compare the field's signatures: FieldReference getField = (FieldReference)initialValue.Operand; FieldReference setField = (FieldReference)expr.Operand; if (!(TypeAnalysis.IsSameType(getField.DeclaringType, setField.DeclaringType) && getField.Name == setField.Name && TypeAnalysis.IsSameType(getField.FieldType, setField.FieldType))) { return(null); } } else if (expr.Code == ILCode.Stobj) { if (!(initialValue.Code == ILCode.Ldobj && initialValue.Operand == expr.Operand)) { return(null); } } else if (expr.Code == ILCode.CallSetter) { if (!(initialValue.Code == ILCode.CallGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand))) { return(null); } } else if (expr.Code == ILCode.CallvirtSetter) { if (!(initialValue.Code == ILCode.CallvirtGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand))) { return(null); } } else { if (!initialValue.Code.IsLoadFromArray()) { return(null); } } Debug.Assert(expr.Arguments.Count - 1 == initialValue.Arguments.Count); for (int i = 0; i < initialValue.Arguments.Count; i++) { if (!initialValue.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand)) { return(null); } } ILExpression stloc = addExpr.Arguments[0]; if (expr.Code == ILCode.Stobj) { stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue.Arguments[0]); } else if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter) { initialValue = new ILExpression(ILCode.AddressOf, null, initialValue); stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue); } else { stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue); initialValue.Code = (expr.Code == ILCode.Stfld ? ILCode.Ldflda : ILCode.Ldelema); } // TODO: ILRanges? return(stloc); }