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);
        }