From 48f344ed03d9299f7f64c03253e6888e507d8e11 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Mon, 25 Sep 2017 02:08:39 +0200 Subject: [PATCH] Add another pattern for generics/nullable using. --- .../IL/Transforms/NullableLiftingTransform.cs | 4 +-- .../IL/Transforms/UsingTransform.cs | 28 ++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs index d0dd236a8..5dac303ed 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs @@ -610,7 +610,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// /// Matches 'call Nullable{T}.GetValueOrDefault(ldloca v)' /// - static bool MatchGetValueOrDefault(ILInstruction inst, out ILVariable v) + internal static bool MatchGetValueOrDefault(ILInstruction inst, out ILVariable v) { v = null; return MatchGetValueOrDefault(inst, out ILInstruction arg) @@ -620,7 +620,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// /// Matches 'call Nullable{T}.GetValueOrDefault(ldloca v)' /// - static bool MatchGetValueOrDefault(ILInstruction inst, ILVariable v) + internal static bool MatchGetValueOrDefault(ILInstruction inst, ILVariable v) { return MatchGetValueOrDefault(inst, out ILVariable v2) && v == v2; } diff --git a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs index 2f3cd1f85..ae283c790 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs @@ -78,13 +78,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(tryFinally))) return false; - if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(tryFinally))) + if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(tryFinally) || (la.IsDescendantOf(tryFinally.TryBlock) && !ILInlining.IsUsedAsThisPointerInCall(la)))) return false; if (storeInst.Variable.StoreInstructions.OfType().Any(st => st != storeInst)) return false; if (!(tryFinally.FinallyBlock is BlockContainer container) || !MatchDisposeBlock(container, storeInst.Variable, storeInst.Value.MatchLdNull())) return false; context.Step("UsingTransform", tryFinally); + storeInst.Variable.Kind = VariableKind.UsingLocal; block.Instructions.RemoveAt(i); block.Instructions[i - 1] = new UsingInstruction(storeInst.Variable, storeInst.Value, tryFinally.TryBlock); return true; @@ -129,13 +130,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (callVirt.Arguments.Count != 1) return false; var firstArg = cv.Arguments.FirstOrDefault(); - if (!(firstArg.MatchUnboxAny(out var innerArg1, out var unboxType) && unboxType.IsKnownType(KnownTypeCode.IDisposable))) - return false; - if (!(innerArg1.MatchBox(out firstArg, out var boxType) && boxType.IsKnownType(KnownTypeCode.NullableOfT) && + if (!(firstArg.MatchUnboxAny(out var innerArg1, out var unboxType) && unboxType.IsKnownType(KnownTypeCode.IDisposable))) { + if (!firstArg.MatchAddressOf(out var innerArg2)) + return false; + return NullableLiftingTransform.MatchGetValueOrDefault(innerArg2, objVar); + } else { + if (!(innerArg1.MatchBox(out firstArg, out var boxType) && boxType.IsKnownType(KnownTypeCode.NullableOfT) && NullableType.GetUnderlyingType(boxType).Equals(NullableType.GetUnderlyingType(objVar.Type)))) - return false; - return firstArg.MatchLdLoc(objVar); + return false; + return firstArg.MatchLdLoc(objVar); + } } else { + ILInstruction target; if (isReference) { // reference types have a null check. if (!entryPoint.Instructions[checkIndex].MatchIfInstruction(out var condition, out var disposeInst)) @@ -146,10 +152,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; if (!(disposeBlock.Instructions[0] is CallVirt cv)) return false; + target = cv.Arguments.FirstOrDefault(); + if (target == null) + return false; + if (target.MatchBox(out var newTarget, out var type) && type.Equals(objVar.Type)) + target = newTarget; callVirt = cv; } else { if (!(entryPoint.Instructions[checkIndex] is CallVirt cv)) return false; + target = cv.Arguments.FirstOrDefault(); + if (target == null) + return false; callVirt = cv; } if (callVirt.Method.FullName != "System.IDisposable.Dispose") @@ -158,7 +172,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; if (callVirt.Arguments.Count != 1) return false; - return callVirt.Arguments[0].MatchLdLocRef(objVar) || (usingNull && callVirt.Arguments[0].MatchLdNull()); + return target.MatchLdLocRef(objVar) || (usingNull && callVirt.Arguments[0].MatchLdNull()); } } }