|
|
|
@ -1,4 +1,5 @@
@@ -1,4 +1,5 @@
|
|
|
|
|
// Copyright (c) 2014 Daniel Grunwald
|
|
|
|
|
#nullable enable |
|
|
|
|
// Copyright (c) 2014 Daniel Grunwald
|
|
|
|
|
//
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
|
|
|
// software and associated documentation files (the "Software"), to deal in the Software
|
|
|
|
@ -16,8 +17,9 @@
@@ -16,8 +17,9 @@
|
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
|
|
using ICSharpCode.Decompiler.TypeSystem; |
|
|
|
|
using System.Diagnostics.CodeAnalysis; |
|
|
|
|
|
|
|
|
|
using ICSharpCode.Decompiler.TypeSystem; |
|
|
|
|
namespace ICSharpCode.Decompiler.IL |
|
|
|
|
{ |
|
|
|
|
partial class ILInstruction |
|
|
|
@ -73,13 +75,13 @@ namespace ICSharpCode.Decompiler.IL
@@ -73,13 +75,13 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return MatchLdcI(out long v) && v == val; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLdLoc(ILVariable variable) |
|
|
|
|
public bool MatchLdLoc(ILVariable? variable) |
|
|
|
|
{ |
|
|
|
|
var inst = this as LdLoc; |
|
|
|
|
return inst != null && inst.Variable == variable; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLdLoca(ILVariable variable) |
|
|
|
|
public bool MatchLdLoca(ILVariable? variable) |
|
|
|
|
{ |
|
|
|
|
var inst = this as LdLoca; |
|
|
|
|
return inst != null && inst.Variable == variable; |
|
|
|
@ -88,7 +90,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -88,7 +90,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Matches either ldloc (if the variable is a reference type), or ldloca (otherwise).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchLdLocRef(ILVariable variable) |
|
|
|
|
public bool MatchLdLocRef(ILVariable? variable) |
|
|
|
|
{ |
|
|
|
|
return MatchLdLocRef(out var v) && v == variable; |
|
|
|
|
} |
|
|
|
@ -96,7 +98,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -96,7 +98,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Matches either ldloc (if the variable is a reference type), or ldloca (otherwise).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchLdLocRef(out ILVariable variable) |
|
|
|
|
public bool MatchLdLocRef([NotNullWhen(true)] out ILVariable? variable) |
|
|
|
|
{ |
|
|
|
|
switch (this) |
|
|
|
|
{ |
|
|
|
@ -118,7 +120,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -118,7 +120,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return inst != null && inst.Variable.Kind == VariableKind.Parameter && inst.Variable.Index < 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchStLoc(out ILVariable variable) |
|
|
|
|
public bool MatchStLoc([NotNullWhen(true)] out ILVariable? variable) |
|
|
|
|
{ |
|
|
|
|
var inst = this as StLoc; |
|
|
|
|
if (inst != null) |
|
|
|
@ -130,7 +132,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -130,7 +132,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchStLoc(ILVariable variable, out ILInstruction value) |
|
|
|
|
public bool MatchStLoc(ILVariable? variable, [NotNullWhen(true)] out ILInstruction? value) |
|
|
|
|
{ |
|
|
|
|
var inst = this as StLoc; |
|
|
|
|
if (inst != null && inst.Variable == variable) |
|
|
|
@ -142,7 +144,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -142,7 +144,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLdLen(StackType type, out ILInstruction array) |
|
|
|
|
public bool MatchLdLen(StackType type, [NotNullWhen(true)] out ILInstruction? array) |
|
|
|
|
{ |
|
|
|
|
var inst = this as LdLen; |
|
|
|
|
if (inst != null && inst.ResultType == type) |
|
|
|
@ -154,7 +156,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -154,7 +156,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchReturn(out ILInstruction value) |
|
|
|
|
public bool MatchReturn([NotNullWhen(true)] out ILInstruction? value) |
|
|
|
|
{ |
|
|
|
|
var inst = this as Leave; |
|
|
|
|
if (inst != null && inst.IsLeavingFunction) |
|
|
|
@ -166,7 +168,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -166,7 +168,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchBranch(out Block targetBlock) |
|
|
|
|
public bool MatchBranch([NotNullWhen(true)] out Block? targetBlock) |
|
|
|
|
{ |
|
|
|
|
var inst = this as Branch; |
|
|
|
|
if (inst != null) |
|
|
|
@ -178,13 +180,13 @@ namespace ICSharpCode.Decompiler.IL
@@ -178,13 +180,13 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchBranch(Block targetBlock) |
|
|
|
|
public bool MatchBranch(Block? targetBlock) |
|
|
|
|
{ |
|
|
|
|
var inst = this as Branch; |
|
|
|
|
return inst != null && inst.TargetBlock == targetBlock; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLeave(out BlockContainer targetContainer, out ILInstruction value) |
|
|
|
|
public bool MatchLeave([NotNullWhen(true)] out BlockContainer? targetContainer, [NotNullWhen(true)] out ILInstruction? value) |
|
|
|
|
{ |
|
|
|
|
var inst = this as Leave; |
|
|
|
|
if (inst != null) |
|
|
|
@ -198,7 +200,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -198,7 +200,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLeave(BlockContainer targetContainer, out ILInstruction value) |
|
|
|
|
public bool MatchLeave(BlockContainer? targetContainer, [NotNullWhen(true)] out ILInstruction? value) |
|
|
|
|
{ |
|
|
|
|
var inst = this as Leave; |
|
|
|
|
if (inst != null && targetContainer == inst.TargetContainer) |
|
|
|
@ -210,7 +212,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -210,7 +212,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLeave(out BlockContainer targetContainer) |
|
|
|
|
public bool MatchLeave([NotNullWhen(true)] out BlockContainer? targetContainer) |
|
|
|
|
{ |
|
|
|
|
var inst = this as Leave; |
|
|
|
|
if (inst != null && inst.Value.MatchNop()) |
|
|
|
@ -222,16 +224,15 @@ namespace ICSharpCode.Decompiler.IL
@@ -222,16 +224,15 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLeave(BlockContainer targetContainer) |
|
|
|
|
public bool MatchLeave(BlockContainer? targetContainer) |
|
|
|
|
{ |
|
|
|
|
var inst = this as Leave; |
|
|
|
|
return inst != null && inst.TargetContainer == targetContainer && inst.Value.MatchNop(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst, out ILInstruction falseInst) |
|
|
|
|
public bool MatchIfInstruction([NotNullWhen(true)] out ILInstruction? condition, [NotNullWhen(true)] out ILInstruction? trueInst, [NotNullWhen(true)] out ILInstruction? falseInst) |
|
|
|
|
{ |
|
|
|
|
var inst = this as IfInstruction; |
|
|
|
|
if (inst != null) |
|
|
|
|
if (this is IfInstruction inst) |
|
|
|
|
{ |
|
|
|
|
condition = inst.Condition; |
|
|
|
|
trueInst = inst.TrueInst; |
|
|
|
@ -244,7 +245,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -244,7 +245,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchIfInstructionPositiveCondition(out ILInstruction condition, out ILInstruction trueInst, out ILInstruction falseInst) |
|
|
|
|
public bool MatchIfInstructionPositiveCondition([NotNullWhen(true)] out ILInstruction? condition, [NotNullWhen(true)] out ILInstruction? trueInst, [NotNullWhen(true)] out ILInstruction? falseInst) |
|
|
|
|
{ |
|
|
|
|
if (MatchIfInstruction(out condition, out trueInst, out falseInst)) |
|
|
|
|
{ |
|
|
|
@ -252,7 +253,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -252,7 +253,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
while (condition.MatchLogicNot(out var arg)) |
|
|
|
|
{ |
|
|
|
|
condition = arg; |
|
|
|
|
ILInstruction tmp = trueInst; |
|
|
|
|
ILInstruction? tmp = trueInst; |
|
|
|
|
trueInst = falseInst; |
|
|
|
|
falseInst = tmp; |
|
|
|
|
} |
|
|
|
@ -264,7 +265,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -264,7 +265,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Matches an if instruction where the false instruction is a nop.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst) |
|
|
|
|
public bool MatchIfInstruction([NotNullWhen(true)] out ILInstruction? condition, [NotNullWhen(true)] out ILInstruction? trueInst) |
|
|
|
|
{ |
|
|
|
|
var inst = this as IfInstruction; |
|
|
|
|
if (inst != null && inst.FalseInst.MatchNop()) |
|
|
|
@ -283,7 +284,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -283,7 +284,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// Note: unlike C# '&&', this instruction is not limited to booleans,
|
|
|
|
|
/// but allows passing through arbitrary I4 values on the rhs (but not on the lhs).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchLogicAnd(out ILInstruction lhs, out ILInstruction rhs) |
|
|
|
|
public bool MatchLogicAnd([NotNullWhen(true)] out ILInstruction? lhs, [NotNullWhen(true)] out ILInstruction? rhs) |
|
|
|
|
{ |
|
|
|
|
var inst = this as IfInstruction; |
|
|
|
|
if (inst != null && inst.FalseInst.MatchLdcI4(0)) |
|
|
|
@ -302,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -302,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// Note: unlike C# '||', this instruction is not limited to booleans,
|
|
|
|
|
/// but allows passing through arbitrary I4 values on the rhs (but not on the lhs).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchLogicOr(out ILInstruction lhs, out ILInstruction rhs) |
|
|
|
|
public bool MatchLogicOr([NotNullWhen(true)] out ILInstruction? lhs, [NotNullWhen(true)] out ILInstruction? rhs) |
|
|
|
|
{ |
|
|
|
|
var inst = this as IfInstruction; |
|
|
|
|
if (inst != null && inst.TrueInst.MatchLdcI4(1)) |
|
|
|
@ -319,7 +320,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -319,7 +320,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Matches an logical negation.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchLogicNot(out ILInstruction arg) |
|
|
|
|
public bool MatchLogicNot([NotNullWhen(true)] out ILInstruction? arg) |
|
|
|
|
{ |
|
|
|
|
if (this is Comp comp && comp.Kind == ComparisonKind.Equality |
|
|
|
|
&& comp.LiftingKind == ComparisonLiftingKind.None |
|
|
|
@ -332,7 +333,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -332,7 +333,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchTryCatchHandler(out ILVariable variable) |
|
|
|
|
public bool MatchTryCatchHandler([NotNullWhen(true)] out ILVariable? variable) |
|
|
|
|
{ |
|
|
|
|
var inst = this as TryCatchHandler; |
|
|
|
|
if (inst != null) |
|
|
|
@ -347,7 +348,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -347,7 +348,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Matches comp(left == right) or logic.not(comp(left != right)).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchCompEquals(out ILInstruction left, out ILInstruction right) |
|
|
|
|
public bool MatchCompEquals([NotNullWhen(true)] out ILInstruction? left, [NotNullWhen(true)] out ILInstruction? right) |
|
|
|
|
{ |
|
|
|
|
ILInstruction thisInst = this; |
|
|
|
|
var compKind = ComparisonKind.Equality; |
|
|
|
@ -376,7 +377,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -376,7 +377,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Matches 'comp(arg == ldnull)'
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchCompEqualsNull(out ILInstruction arg) |
|
|
|
|
public bool MatchCompEqualsNull([NotNullWhen(true)] out ILInstruction? arg) |
|
|
|
|
{ |
|
|
|
|
if (!MatchCompEquals(out var left, out var right)) |
|
|
|
|
{ |
|
|
|
@ -403,7 +404,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -403,7 +404,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Matches 'comp(arg != ldnull)'
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchCompNotEqualsNull(out ILInstruction arg) |
|
|
|
|
public bool MatchCompNotEqualsNull([NotNullWhen(true)] out ILInstruction? arg) |
|
|
|
|
{ |
|
|
|
|
if (!MatchCompNotEquals(out var left, out var right)) |
|
|
|
|
{ |
|
|
|
@ -430,7 +431,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -430,7 +431,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Matches comp(left != right) or logic.not(comp(left == right)).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool MatchCompNotEquals(out ILInstruction left, out ILInstruction right) |
|
|
|
|
public bool MatchCompNotEquals([NotNullWhen(true)] out ILInstruction? left, [NotNullWhen(true)] out ILInstruction? right) |
|
|
|
|
{ |
|
|
|
|
ILInstruction thisInst = this; |
|
|
|
|
var compKind = ComparisonKind.Inequality; |
|
|
|
@ -456,7 +457,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -456,7 +457,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLdFld(out ILInstruction target, out IField field) |
|
|
|
|
public bool MatchLdFld([NotNullWhen(true)] out ILInstruction? target, [NotNullWhen(true)] out IField? field) |
|
|
|
|
{ |
|
|
|
|
if (this is LdObj ldobj && ldobj.Target is LdFlda ldflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile) |
|
|
|
|
{ |
|
|
|
@ -472,7 +473,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -472,7 +473,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLdsFld(out IField field) |
|
|
|
|
public bool MatchLdsFld([NotNullWhen(true)] out IField? field) |
|
|
|
|
{ |
|
|
|
|
if (this is LdObj ldobj && ldobj.Target is LdsFlda ldsflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile) |
|
|
|
|
{ |
|
|
|
@ -483,12 +484,12 @@ namespace ICSharpCode.Decompiler.IL
@@ -483,12 +484,12 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchLdsFld(IField field) |
|
|
|
|
public bool MatchLdsFld(IField? field) |
|
|
|
|
{ |
|
|
|
|
return MatchLdsFld(out var f) && f.Equals(field); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchStsFld(out IField field, out ILInstruction value) |
|
|
|
|
public bool MatchStsFld([NotNullWhen(true)] out IField? field, [NotNullWhen(true)] out ILInstruction? value) |
|
|
|
|
{ |
|
|
|
|
if (this is StObj stobj && stobj.Target is LdsFlda ldsflda && stobj.UnalignedPrefix == 0 && !stobj.IsVolatile) |
|
|
|
|
{ |
|
|
|
@ -501,7 +502,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -501,7 +502,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchStFld(out ILInstruction target, out IField field, out ILInstruction value) |
|
|
|
|
public bool MatchStFld([NotNullWhen(true)] out ILInstruction? target, [NotNullWhen(true)] out IField? field, [NotNullWhen(true)] out ILInstruction? value) |
|
|
|
|
{ |
|
|
|
|
if (this is StObj stobj && stobj.Target is LdFlda ldflda && stobj.UnalignedPrefix == 0 && !stobj.IsVolatile) |
|
|
|
|
{ |
|
|
|
@ -522,7 +523,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -522,7 +523,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return op != null && op.Operator == @operator; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchBinaryNumericInstruction(BinaryNumericOperator @operator, out ILInstruction left, out ILInstruction right) |
|
|
|
|
public bool MatchBinaryNumericInstruction(BinaryNumericOperator @operator, [NotNullWhen(true)] out ILInstruction? left, [NotNullWhen(true)] out ILInstruction? right) |
|
|
|
|
{ |
|
|
|
|
var op = this as BinaryNumericInstruction; |
|
|
|
|
if (op != null && op.Operator == @operator) |
|
|
|
@ -536,7 +537,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -536,7 +537,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool MatchBinaryNumericInstruction(out BinaryNumericOperator @operator, out ILInstruction left, out ILInstruction right) |
|
|
|
|
public bool MatchBinaryNumericInstruction(out BinaryNumericOperator @operator, [NotNullWhen(true)] out ILInstruction? left, [NotNullWhen(true)] out ILInstruction? right) |
|
|
|
|
{ |
|
|
|
|
var op = this as BinaryNumericInstruction; |
|
|
|
|
if (op != null) |
|
|
|
|