diff --git a/ICSharpCode.Decompiler/ILAst/ILInlining.cs b/ICSharpCode.Decompiler/ILAst/ILInlining.cs index c1c904951..ea88c3206 100644 --- a/ICSharpCode.Decompiler/ILAst/ILInlining.cs +++ b/ICSharpCode.Decompiler/ILAst/ILInlining.cs @@ -169,7 +169,10 @@ namespace ICSharpCode.Decompiler.ILAst bool InlineIfPossible(ILVariable v, ILExpression inlinedExpression, ILNode next, bool aggressive) { // ensure the variable is accessed only a single time - if (!(numStloc.GetOrDefault(v) == 1 && numLdloc.GetOrDefault(v) == 1 && numLdloca.GetOrDefault(v) == 0)) + if (numStloc.GetOrDefault(v) != 1) + return false; + int ldloc = numLdloc.GetOrDefault(v); + if (ldloc > 1 || ldloc + numLdloca.GetOrDefault(v) != 1) return false; if (next is ILCondition) @@ -180,7 +183,12 @@ namespace ICSharpCode.Decompiler.ILAst ILExpression parent; int pos; if (FindLoadInNext(next as ILExpression, v, inlinedExpression, out parent, out pos) == true) { - if (!aggressive && !v.IsGenerated && !NonAggressiveInlineInto((ILExpression)next, parent, inlinedExpression)) + if (ldloc == 0) + { + if (!IsGeneratedValueTypeTemporary((ILExpression)next, parent, pos, v)) + return false; + } + else if (!aggressive && !v.IsGenerated && !NonAggressiveInlineInto((ILExpression)next, parent, inlinedExpression)) return false; // Assign the ranges of the ldloc instruction: @@ -192,6 +200,15 @@ namespace ICSharpCode.Decompiler.ILAst } return false; } + + /// + /// Is this a temporary variable generated by the C# compiler for instance method calls on immutable value type values + /// + bool IsGeneratedValueTypeTemporary(ILExpression next, ILExpression parent, int pos, ILVariable v) + { + return pos == 0 && v.Type != null && v.Type.IsValueType && next.Code == ILCode.Stloc + && (parent.Code == ILCode.Call || parent.Code == ILCode.Callvirt) && ((MethodReference)parent.Operand).HasThis; + } bool NonAggressiveInlineInto(ILExpression next, ILExpression parent, ILExpression inlinedExpression) { @@ -214,7 +231,7 @@ namespace ICSharpCode.Decompiler.ILAst return false; } } - + /// /// Gets whether 'expressionBeingMoved' can be inlined into 'expr'. /// @@ -243,7 +260,7 @@ namespace ICSharpCode.Decompiler.ILAst ILExpression arg = expr.Arguments[i]; - if (arg.Code == ILCode.Ldloc && arg.Operand == v) { + if ((arg.Code == ILCode.Ldloc || arg.Code == ILCode.Ldloca) && arg.Operand == v) { parent = expr; pos = i; return true;