From 875af13934f94610a0d56b17bf164fbdf59d99b1 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 22 Dec 2018 11:47:32 +0100 Subject: [PATCH] Fix #750: Missing recognizer for ?? when rhs is an assignment expression --- .../IL/Transforms/NullCoalescingTransform.cs | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs index 151d29092..0717bc112 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs @@ -55,11 +55,29 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; if (!block.Instructions[pos + 1].MatchIfInstruction(out var condition, out var trueInst)) return false; + if (!(condition.MatchCompEquals(out var left, out var right) && left.MatchLdLoc(stloc.Variable) && right.MatchLdNull())) + return false; trueInst = Block.Unwrap(trueInst); - if (condition.MatchCompEquals(out var left, out var right) && left.MatchLdLoc(stloc.Variable) && right.MatchLdNull() - && trueInst.MatchStLoc(stloc.Variable, out var fallbackValue) - ) { - context.Step("NullCoalescingTransform (reference types)", stloc); + if (trueInst.MatchStLoc(stloc.Variable, out var fallbackValue)) { + context.Step("NullCoalescingTransform: simple (reference types)", stloc); + stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue); + block.Instructions.RemoveAt(pos + 1); // remove if instruction + ILInlining.InlineOneIfPossible(block, pos, InliningOptions.None, context); + return true; + } + // sometimes the compiler generates: + // stloc s(valueInst) + // if (comp(ldloc s == ldnull)) { + // stloc v(fallbackInst) + // stloc s(ldloc v) + // } + // v must be single-assign and single-use. + if (trueInst is Block trueBlock && trueBlock.Instructions.Count == 2 + && trueBlock.Instructions[0].MatchStLoc(out var temporary, out fallbackValue) + && temporary.IsSingleDefinition && temporary.LoadCount == 1 + && trueBlock.Instructions[1].MatchStLoc(stloc.Variable, out var useOfTemporary) + && useOfTemporary.MatchLdLoc(temporary)) { + context.Step("NullCoalescingTransform: with temporary variable (reference types)", stloc); stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue); block.Instructions.RemoveAt(pos + 1); // remove if instruction ILInlining.InlineOneIfPossible(block, pos, InliningOptions.None, context);