Browse Source

Add another pattern for generics/nullable using.

pull/877/head
Siegfried Pammer 8 years ago
parent
commit
48f344ed03
  1. 4
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
  2. 28
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

4
ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

@ -610,7 +610,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary> /// <summary>
/// Matches 'call Nullable{T}.GetValueOrDefault(ldloca v)' /// Matches 'call Nullable{T}.GetValueOrDefault(ldloca v)'
/// </summary> /// </summary>
static bool MatchGetValueOrDefault(ILInstruction inst, out ILVariable v) internal static bool MatchGetValueOrDefault(ILInstruction inst, out ILVariable v)
{ {
v = null; v = null;
return MatchGetValueOrDefault(inst, out ILInstruction arg) return MatchGetValueOrDefault(inst, out ILInstruction arg)
@ -620,7 +620,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary> /// <summary>
/// Matches 'call Nullable{T}.GetValueOrDefault(ldloca v)' /// Matches 'call Nullable{T}.GetValueOrDefault(ldloca v)'
/// </summary> /// </summary>
static bool MatchGetValueOrDefault(ILInstruction inst, ILVariable v) internal static bool MatchGetValueOrDefault(ILInstruction inst, ILVariable v)
{ {
return MatchGetValueOrDefault(inst, out ILVariable v2) && v == v2; return MatchGetValueOrDefault(inst, out ILVariable v2) && v == v2;
} }

28
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -78,13 +78,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(tryFinally))) if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(tryFinally)))
return false; 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; return false;
if (storeInst.Variable.StoreInstructions.OfType<ILInstruction>().Any(st => st != storeInst)) if (storeInst.Variable.StoreInstructions.OfType<ILInstruction>().Any(st => st != storeInst))
return false; return false;
if (!(tryFinally.FinallyBlock is BlockContainer container) || !MatchDisposeBlock(container, storeInst.Variable, storeInst.Value.MatchLdNull())) if (!(tryFinally.FinallyBlock is BlockContainer container) || !MatchDisposeBlock(container, storeInst.Variable, storeInst.Value.MatchLdNull()))
return false; return false;
context.Step("UsingTransform", tryFinally); context.Step("UsingTransform", tryFinally);
storeInst.Variable.Kind = VariableKind.UsingLocal;
block.Instructions.RemoveAt(i); block.Instructions.RemoveAt(i);
block.Instructions[i - 1] = new UsingInstruction(storeInst.Variable, storeInst.Value, tryFinally.TryBlock); block.Instructions[i - 1] = new UsingInstruction(storeInst.Variable, storeInst.Value, tryFinally.TryBlock);
return true; return true;
@ -129,13 +130,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (callVirt.Arguments.Count != 1) if (callVirt.Arguments.Count != 1)
return false; return false;
var firstArg = cv.Arguments.FirstOrDefault(); var firstArg = cv.Arguments.FirstOrDefault();
if (!(firstArg.MatchUnboxAny(out var innerArg1, out var unboxType) && unboxType.IsKnownType(KnownTypeCode.IDisposable))) if (!(firstArg.MatchUnboxAny(out var innerArg1, out var unboxType) && unboxType.IsKnownType(KnownTypeCode.IDisposable))) {
return false; if (!firstArg.MatchAddressOf(out var innerArg2))
if (!(innerArg1.MatchBox(out firstArg, out var boxType) && boxType.IsKnownType(KnownTypeCode.NullableOfT) && 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)))) NullableType.GetUnderlyingType(boxType).Equals(NullableType.GetUnderlyingType(objVar.Type))))
return false; return false;
return firstArg.MatchLdLoc(objVar); return firstArg.MatchLdLoc(objVar);
}
} else { } else {
ILInstruction target;
if (isReference) { if (isReference) {
// reference types have a null check. // reference types have a null check.
if (!entryPoint.Instructions[checkIndex].MatchIfInstruction(out var condition, out var disposeInst)) if (!entryPoint.Instructions[checkIndex].MatchIfInstruction(out var condition, out var disposeInst))
@ -146,10 +152,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!(disposeBlock.Instructions[0] is CallVirt cv)) if (!(disposeBlock.Instructions[0] is CallVirt cv))
return false; 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; callVirt = cv;
} else { } else {
if (!(entryPoint.Instructions[checkIndex] is CallVirt cv)) if (!(entryPoint.Instructions[checkIndex] is CallVirt cv))
return false; return false;
target = cv.Arguments.FirstOrDefault();
if (target == null)
return false;
callVirt = cv; callVirt = cv;
} }
if (callVirt.Method.FullName != "System.IDisposable.Dispose") if (callVirt.Method.FullName != "System.IDisposable.Dispose")
@ -158,7 +172,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (callVirt.Arguments.Count != 1) if (callVirt.Arguments.Count != 1)
return false; return false;
return callVirt.Arguments[0].MatchLdLocRef(objVar) || (usingNull && callVirt.Arguments[0].MatchLdNull()); return target.MatchLdLocRef(objVar) || (usingNull && callVirt.Arguments[0].MatchLdNull());
} }
} }
} }

Loading…
Cancel
Save