Browse Source

Merge #166 Fix split local variable post-increment recognition

pull/170/merge
Daniel Grunwald 14 years ago
parent
commit
0cae9b4983
  1. 55
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  2. 6
      ICSharpCode.Decompiler/Tests/IncrementDecrement.cs

55
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -440,6 +440,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -440,6 +440,7 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
#region IntroducePostIncrement
bool IntroducePostIncrement(List<ILNode> body, ILExpression expr, int pos)
{
bool modified = IntroducePostIncrementForVariables(body, expr, pos);
@ -453,6 +454,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -453,6 +454,13 @@ namespace ICSharpCode.Decompiler.ILAst
return modified;
}
private static IDictionary<ILCode, ILCode> _postIncrementPairs = new Dictionary<ILCode, ILCode>
{
{ILCode.Ldloc, ILCode.Stloc},
{ILCode.Ldsfld, ILCode.Stsfld},
{ILCode.CallGetter, ILCode.CallSetter}
};
bool IntroducePostIncrementForVariables(List<ILNode> body, ILExpression expr, int pos)
{
// Works for variables and static fields/properties
@ -465,19 +473,40 @@ namespace ICSharpCode.Decompiler.ILAst @@ -465,19 +473,40 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression exprInit;
if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated))
return false;
if (!(exprInit.Code == ILCode.Ldloc || exprInit.Code == ILCode.Ldsfld || (exprInit.Code == ILCode.CallGetter && exprInit.Arguments.Count == 0)))
ILCode loadInstruction = exprInit.Code;
//We only recognise local variables, fields & getters with no arguments
if (!_postIncrementPairs.ContainsKey(loadInstruction))
return false;
if (loadInstruction == ILCode.CallGetter && exprInit.Arguments.Count != 0)
return false;
//The next expression
ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
if (nextExpr == null)
return false;
if (exprInit.Code == ILCode.CallGetter) {
if (!(nextExpr.Code == ILCode.CallSetter && IsGetterSetterPair(exprInit.Operand, nextExpr.Operand)))
ILCode storeInstruction = nextExpr.Code;
//Must be a matching store type
if (_postIncrementPairs[loadInstruction] != storeInstruction)
return false;
} else {
if (!(nextExpr.Code == (exprInit.Code == ILCode.Ldloc ? ILCode.Stloc : ILCode.Stsfld) && nextExpr.Operand == exprInit.Operand))
object nextExprOperand = nextExpr.Operand;
object exprInitOperand = exprInit.Operand;
if (loadInstruction == ILCode.CallGetter)
if (!IsGetterSetterPair(exprInitOperand, nextExprOperand))
return false;
}
if (loadInstruction == ILCode.Ldloc)
if ((nextExprOperand != exprInitOperand))
if (((ILVariable) nextExprOperand).OriginalVariable == ((ILVariable) exprInitOperand).OriginalVariable)
//Spit local variable, unsplit these two instances
foreach (var ilExpression in body.SelectMany(
node => node.GetSelfAndChildrenRecursive<ILExpression>(
expression => expression.Operand == nextExprOperand)))
ilExpression.Operand = exprInitOperand;
else
return false;
ILExpression addExpr = nextExpr.Arguments[0];
int incrementAmount;
@ -485,12 +514,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -485,12 +514,18 @@ namespace ICSharpCode.Decompiler.ILAst
if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar)))
return false;
if (exprInit.Code == ILCode.Ldloc)
switch (loadInstruction)
{
case ILCode.Ldloc:
exprInit.Code = ILCode.Ldloca;
else if (exprInit.Code == ILCode.CallGetter)
exprInit = new ILExpression(ILCode.AddressOf, null, exprInit);
else
break;
case ILCode.Ldsfld:
exprInit.Code = ILCode.Ldsflda;
break;
case ILCode.CallGetter:
exprInit = new ILExpression(ILCode.AddressOf, null, exprInit);
break;
}
expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit);
body.RemoveAt(pos + 1); // TODO ILRanges
return true;

6
ICSharpCode.Decompiler/Tests/IncrementDecrement.cs

@ -176,6 +176,12 @@ public class IncrementDecrement @@ -176,6 +176,12 @@ public class IncrementDecrement
return i++ + j;
}
public void PostIncrementInlineLocalVariable(Func<int, int> f)
{
int num = 0;
f(num++);
}
public int PostIncrementArrayElement(int[] array, int pos)
{
return array[pos]--;

Loading…
Cancel
Save