Browse Source

#nullable enable for Instructions.tt

issue1638
Daniel Grunwald 4 years ago
parent
commit
245261a1e5
  1. 508
      ICSharpCode.Decompiler/IL/Instructions.cs
  2. 83
      ICSharpCode.Decompiler/IL/Instructions.tt
  3. 14
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  4. 6
      ICSharpCode.Decompiler/IL/Instructions/DeconstructResultInstruction.cs
  5. 2
      ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs
  6. 6
      ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs
  7. 15
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  8. 20
      ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs
  9. 4
      ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs
  10. 8
      ICSharpCode.Decompiler/Util/NullAttributes.cs

508
ICSharpCode.Decompiler/IL/Instructions.cs

File diff suppressed because it is too large Load Diff

83
ICSharpCode.Decompiler/IL/Instructions.tt

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #> <#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #> <#@ import namespace="System.Linq" #>
@ -32,7 +34,7 @@
AbstractBaseClass, CustomArguments(("left", null), ("right", null)), HasFlag("InstructionFlags.None")), AbstractBaseClass, CustomArguments(("left", null), ("right", null)), HasFlag("InstructionFlags.None")),
new OpCode("CallInstruction", "Instruction with a list of arguments.", new OpCode("CallInstruction", "Instruction with a list of arguments.",
AbstractBaseClass, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), AbstractBaseClass, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}),
CustomWriteTo, MayThrow, SideEffect), CustomConstructor, CustomWriteTo, MayThrow, SideEffect),
new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("Unknown")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" }, new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("Unknown")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" },
new OpCode("CompoundAssignmentInstruction", "Common instruction for compound assignments.", new OpCode("CompoundAssignmentInstruction", "Common instruction for compound assignments.",
AbstractBaseClass, CustomConstructor, CustomArguments(("target", null), ("value", null))), AbstractBaseClass, CustomConstructor, CustomArguments(("target", null), ("value", null))),
@ -68,7 +70,7 @@
new ChildInfo("init") { CanInlineInto = true }, new ChildInfo("init") { CanInlineInto = true },
new ChildInfo("body") new ChildInfo("body")
}), }),
CustomInvariant("Debug.Assert(Variable.Kind == VariableKind.PinnedRegionLocal);")), CustomInvariant("DebugAssert(Variable.Kind == VariableKind.PinnedRegionLocal);")),
new OpCode("binary", "Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.", new OpCode("binary", "Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.",
CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags, CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags,
MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator && IsLifted == o.IsLifted")), MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator && IsLifted == o.IsLifted")),
@ -215,11 +217,11 @@
new OpCode("ldnull", "Loads the null reference.", new OpCode("ldnull", "Loads the null reference.",
CustomClassName("LdNull"), NoArguments, ResultType("O")), CustomClassName("LdNull"), NoArguments, ResultType("O")),
new OpCode("ldftn", "Load method pointer", new OpCode("ldftn", "Load method pointer",
CustomClassName("LdFtn"), NoArguments, HasMethodOperand, ResultType("I")), CustomClassName("LdFtn"), NoArguments, HasMethodOperand(), ResultType("I")),
new OpCode("ldvirtftn", "Load method pointer", new OpCode("ldvirtftn", "Load method pointer",
CustomClassName("LdVirtFtn"), Unary, HasMethodOperand, MayThrow, ResultType("I")), CustomClassName("LdVirtFtn"), Unary, HasMethodOperand(), MayThrow, ResultType("I")),
new OpCode("ldvirtdelegate", "Virtual delegate construction", new OpCode("ldvirtdelegate", "Virtual delegate construction",
CustomClassName("LdVirtDelegate"), Unary, HasTypeOperand, HasMethodOperand, CustomClassName("LdVirtDelegate"), Unary, HasTypeOperand, HasMethodOperand(),
MayThrow, ResultType("O")), MayThrow, ResultType("O")),
new OpCode("ldtypetoken", "Loads runtime representation of metadata token", new OpCode("ldtypetoken", "Loads runtime representation of metadata token",
CustomClassName("LdTypeToken"), NoArguments, HasTypeOperand, ResultType("O")), CustomClassName("LdTypeToken"), NoArguments, HasTypeOperand, ResultType("O")),
@ -287,7 +289,7 @@
+ "The input must be an object reference (O)." + Environment.NewLine + "The input must be an object reference (O)." + Environment.NewLine
+ "If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty." + Environment.NewLine + "If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty." + Environment.NewLine
+ "Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null." + Environment.NewLine, + "Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null." + Environment.NewLine,
CustomArguments(("argument", new[] { "O" })), ResultType("Ref"), HasMethodOperand), CustomArguments(("argument", new[] { "O" })), ResultType("Ref"), HasMethodOperand(nullable: true)),
new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).", new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).",
CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo, ResultType("I4")), CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo, ResultType("I4")),
@ -297,7 +299,7 @@
new OpCode("user.logic.operator", "Use of user-defined &amp;&amp; or || operator.", new OpCode("user.logic.operator", "Use of user-defined &amp;&amp; or || operator.",
CustomClassName("UserDefinedLogicOperator"), CustomClassName("UserDefinedLogicOperator"),
HasMethodOperand, ResultType("O"), HasMethodOperand(), ResultType("O"),
CustomChildren(new []{ CustomChildren(new []{
new ChildInfo("left") { CanInlineInto = true }, new ChildInfo("left") { CanInlineInto = true },
new ChildInfo("right") { CanInlineInto = false } // only executed depending on value of left new ChildInfo("right") { CanInlineInto = false } // only executed depending on value of left
@ -337,7 +339,7 @@
CustomClassName("DynamicIsEventInstruction"), Dynamic, CustomArguments(("argument", new[] { "O" })), CustomWriteTo), CustomClassName("DynamicIsEventInstruction"), Dynamic, CustomArguments(("argument", new[] { "O" })), CustomWriteTo),
new OpCode("match", "ILAst representation of C# patterns", new OpCode("match", "ILAst representation of C# patterns",
CustomClassName("MatchInstruction"), HasVariableOperand("Store"), HasMethodOperand, CustomClassName("MatchInstruction"), HasVariableOperand("Store"), HasMethodOperand(nullable: true),
BoolFlag("IsDeconstructCall"), BoolFlag("IsDeconstructTuple"), BoolFlag("CheckType"), BoolFlag("CheckNotNull"), BoolFlag("IsDeconstructCall"), BoolFlag("IsDeconstructTuple"), BoolFlag("CheckType"), BoolFlag("CheckNotNull"),
CustomChildren(new []{ CustomChildren(new []{
new ChildInfo("testedOperand") { CanInlineInto = true }, new ChildInfo("testedOperand") { CanInlineInto = true },
@ -371,8 +373,8 @@
}; };
#> #>
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -437,7 +439,7 @@ namespace <#=opCode.Namespace#>
} }
<# } #> <# } #>
<# if (opCode.GeneratePerformMatch) { #> <# if (opCode.GeneratePerformMatch) { #>
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) protected internal override bool PerformMatch(ILInstruction? other, ref Patterns.Match match)
{ {
var o = other as <#=opCode.Name#>; var o = other as <#=opCode.Name#>;
return <#=string.Join(" && ", opCode.PerformMatchConditions)#>; return <#=string.Join(" && ", opCode.PerformMatchConditions)#>;
@ -637,10 +639,15 @@ namespace ICSharpCode.Decompiler.IL
public string TypeName; public string TypeName;
public string Name; public string Name;
public string FieldName; public string FieldName;
public bool IsReferenceType = true;
public override string ToString() public override string ToString()
{ {
return "out " + TypeName + " " + Name; if (IsReferenceType) {
return "[NotNullWhen(true)] out " + TypeName + "? " + Name;
} else {
return "out " + TypeName + " " + Name;
}
} }
} }
@ -866,7 +873,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.WriteArguments.Add("output.Write(\", \");"); opCode.WriteArguments.Add("output.Write(\", \");");
opCode.WriteArguments.Add("this." + arg + ".WriteTo(output, options);"); opCode.WriteArguments.Add("this." + arg + ".WriteTo(output, options);");
opCode.Members.Add("public static readonly SlotInfo " + children[i].SlotName + " = " + children[i].GetSlotInit() + ";"); opCode.Members.Add("public static readonly SlotInfo " + children[i].SlotName + " = " + children[i].GetSlotInit() + ";");
opCode.Members.Add("ILInstruction " + arg + ";"); opCode.Members.Add("ILInstruction " + arg + " = null!;");
opCode.Members.Add("public ILInstruction " + argProp + " {" + Environment.NewLine opCode.Members.Add("public ILInstruction " + argProp + " {" + Environment.NewLine
+ "\tget { return this." + arg + "; }" + Environment.NewLine + "\tget { return this." + arg + "; }" + Environment.NewLine
+ "\tset {" + Environment.NewLine + "\tset {" + Environment.NewLine
@ -885,7 +892,7 @@ namespace ICSharpCode.Decompiler.IL
checkString += " || "; checkString += " || ";
checkString += arg + ".ResultType == " + expectedTypeCode; checkString += arg + ".ResultType == " + expectedTypeCode;
} }
opCode.Invariants.Add("Debug.Assert(" + checkString + ");"); opCode.Invariants.Add("DebugAssert(" + checkString + ");");
} }
} }
opCode.WriteArguments.Add("output.Write(')');"); opCode.WriteArguments.Add("output.Write(')');");
@ -1008,8 +1015,7 @@ namespace ICSharpCode.Decompiler.IL
Action<OpCode> action = opCode => { Action<OpCode> action = opCode => {
opCode.ConstructorParameters.Add("ILVariable variable"); opCode.ConstructorParameters.Add("ILVariable variable");
opCode.Members.Add("ILVariable variable;"); opCode.Members.Add("ILVariable variable;");
opCode.ConstructorBody.Add("Debug.Assert(variable != null);"); opCode.ConstructorBody.Add("this.variable = variable ?? throw new ArgumentNullException(nameof(variable));");
opCode.ConstructorBody.Add("this.variable = variable;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILVariable", Name = "variable", FieldName = "Variable" }); opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILVariable", Name = "variable", FieldName = "Variable" });
opCode.PerformMatchConditions.Add("variable == o.variable"); opCode.PerformMatchConditions.Add("variable == o.variable");
opCode.GenerateWriteTo = true; opCode.GenerateWriteTo = true;
@ -1019,7 +1025,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.Members.Add(@"public ILVariable Variable { opCode.Members.Add(@"public ILVariable Variable {
get { return variable; } get { return variable; }
set { set {
Debug.Assert(value != null); DebugAssert(value != null);
if (IsConnected) if (IsConnected)
variable.RemoveAccessInstruction(this); variable.RemoveAccessInstruction(this);
variable = value; variable = value;
@ -1048,8 +1054,8 @@ protected override void Disconnected()
} }
".Replace("Access", accessType)); ".Replace("Access", accessType));
if (generateCheckInvariant) { if (generateCheckInvariant) {
opCode.Invariants.Add("Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));"); opCode.Invariants.Add("DebugAssert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function!));");
opCode.Invariants.Add("Debug.Assert(phase <= ILPhase.InILReader || variable.Function.Variables[variable.IndexInFunction] == variable);"); opCode.Invariants.Add("DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);");
} }
}; };
if (accessType == "Load") { if (accessType == "Load") {
@ -1093,21 +1099,25 @@ protected override void Disconnected()
opCode.WriteOperand.Add("type.WriteTo(output);"); opCode.WriteOperand.Add("type.WriteTo(output);");
}; };
static Action<OpCode> HasMethodOperand = opCode => { static Action<OpCode> HasMethodOperand(bool nullable = false)
opCode.ConstructorParameters.Add("IMethod method"); {
opCode.Members.Add("readonly IMethod method;"); return opCode => {
opCode.ConstructorBody.Add("this.method = method;"); string n = nullable ? "?" : "";
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IMethod", Name = "method", FieldName = "Method" }); opCode.ConstructorParameters.Add($"IMethod{n} method");
opCode.PerformMatchConditions.Add("object.Equals(method, o.method)"); opCode.Members.Add($"readonly IMethod{n} method;");
opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine opCode.ConstructorBody.Add("this.method = method;");
+ "public IMethod Method { get { return method; } }"); opCode.MatchParameters.Add(new MatchParamInfo { TypeName = $"IMethod{n}", Name = "method", FieldName = "Method", IsReferenceType = !nullable });
opCode.GenerateWriteTo = true; opCode.PerformMatchConditions.Add("object.Equals(method, o.method)");
opCode.WriteOperand.Add("if (method != null) {"); opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine
opCode.WriteOperand.Add("\toutput.Write(' ');"); + $"public IMethod{n} Method => method;");
opCode.WriteOperand.Add("\tmethod.WriteTo(output);"); opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("}"); opCode.WriteOperand.Add("if (method != null) {");
opCode.Interfaces.Add("IInstructionWithMethodOperand"); opCode.WriteOperand.Add("\toutput.Write(' ');");
}; opCode.WriteOperand.Add("\tmethod.WriteTo(output);");
opCode.WriteOperand.Add("}");
opCode.Interfaces.Add("IInstructionWithMethodOperand");
};
}
static Action<OpCode> HasMemberOperand = opCode => { static Action<OpCode> HasMemberOperand = opCode => {
opCode.ConstructorParameters.Add("IMember member"); opCode.ConstructorParameters.Add("IMember member");
@ -1139,7 +1149,12 @@ protected override void Disconnected()
return opCode => { return opCode => {
NoArguments(opCode); NoArguments(opCode);
opCode.ConstructorParameters.Add(operandType + " value"); opCode.ConstructorParameters.Add(operandType + " value");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = operandType, Name = "value", FieldName = "Value" }); opCode.MatchParameters.Add(new MatchParamInfo {
TypeName = operandType,
Name = "value",
FieldName = "Value",
IsReferenceType = operandType == "string"
});
opCode.PerformMatchConditions.Add("this.Value == o.Value"); opCode.PerformMatchConditions.Add("this.Value == o.Value");
opCode.Members.Add("public readonly " + operandType + " Value;"); opCode.Members.Add("public readonly " + operandType + " Value;");
opCode.ConstructorBody.Add("this.Value = value;"); opCode.ConstructorBody.Add("this.Value = value;");

14
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -124,10 +124,10 @@ namespace ICSharpCode.Decompiler.IL
foreach (var inst in Instructions) foreach (var inst in Instructions)
{ {
var stloc = inst as StLoc; var stloc = inst as StLoc;
Debug.Assert(stloc != null, "Instructions in CallWithNamedArgs must be assignments"); DebugAssert(stloc != null, "Instructions in CallWithNamedArgs must be assignments");
Debug.Assert(stloc!.Variable.Kind == VariableKind.NamedArgument); DebugAssert(stloc.Variable.Kind == VariableKind.NamedArgument);
Debug.Assert(stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 1); DebugAssert(stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 1);
Debug.Assert(stloc.Variable.LoadInstructions.Single().Parent == finalInstruction); DebugAssert(stloc.Variable.LoadInstructions.Single().Parent == finalInstruction);
} }
var call = (CallInstruction)finalInstruction; var call = (CallInstruction)finalInstruction;
if (call.IsInstanceCall) if (call.IsInstanceCall)
@ -144,9 +144,9 @@ namespace ICSharpCode.Decompiler.IL
Debug.Assert(Instructions[0].MatchStLoc(final!.Variable, out var init) && init.MatchNewArr(out type)); Debug.Assert(Instructions[0].MatchStLoc(final!.Variable, out var init) && init.MatchNewArr(out type));
for (int i = 1; i < Instructions.Count; i++) for (int i = 1; i < Instructions.Count; i++)
{ {
Debug.Assert(Instructions[i].MatchStObj(out ILInstruction? target, out _, out var t) && type != null && type.Equals(t)); DebugAssert(Instructions[i].MatchStObj(out ILInstruction? target, out _, out var t) && type != null && type.Equals(t));
Debug.Assert(target.MatchLdElema(out t, out ILInstruction? array) && type!.Equals(t)); DebugAssert(target.MatchLdElema(out t, out ILInstruction? array) && type.Equals(t));
Debug.Assert(array.MatchLdLoc(out ILVariable? v) && v == final.Variable); DebugAssert(array.MatchLdLoc(out ILVariable? v) && v == final.Variable);
} }
break; break;
case BlockKind.CollectionInitializer: case BlockKind.CollectionInitializer:

6
ICSharpCode.Decompiler/IL/Instructions/DeconstructResultInstruction.cs

@ -61,10 +61,10 @@ namespace ICSharpCode.Decompiler.IL
void AdditionalInvariants() void AdditionalInvariants()
{ {
var matchInst = FindMatch(); var matchInst = FindMatch();
Debug.Assert(matchInst != null && (matchInst.IsDeconstructCall || matchInst.IsDeconstructTuple)); DebugAssert(matchInst != null && (matchInst.IsDeconstructCall || matchInst.IsDeconstructTuple));
Debug.Assert(Argument.MatchLdLoc(matchInst!.Variable)); DebugAssert(Argument.MatchLdLoc(matchInst.Variable));
var outParamType = matchInst.GetDeconstructResultType(this.Index); var outParamType = matchInst.GetDeconstructResultType(this.Index);
Debug.Assert(outParamType.GetStackType() == ResultType); DebugAssert(outParamType.GetStackType() == ResultType);
} }
} }
} }

2
ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs

@ -145,7 +145,7 @@ namespace ICSharpCode.Decompiler.IL
public DynamicConvertInstruction(CSharpBinderFlags binderFlags, IType type, IType? context, ILInstruction argument) public DynamicConvertInstruction(CSharpBinderFlags binderFlags, IType type, IType? context, ILInstruction argument)
: base(OpCode.DynamicConvertInstruction, binderFlags, context) : base(OpCode.DynamicConvertInstruction, binderFlags, context)
{ {
Type = type; this.type = type;
Argument = argument; Argument = argument;
} }

6
ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs

@ -1,8 +1,4 @@
#nullable enable #nullable enable
using System;
using System.Collections.Generic;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
@ -14,7 +10,7 @@ namespace ICSharpCode.Decompiler.IL
public ExpressionTreeCast(IType type, ILInstruction argument, bool isChecked) public ExpressionTreeCast(IType type, ILInstruction argument, bool isChecked)
: base(OpCode.ExpressionTreeCast, argument) : base(OpCode.ExpressionTreeCast, argument)
{ {
this.Type = type; this.type = type;
this.IsChecked = isChecked; this.IsChecked = isChecked;
} }

15
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -21,6 +21,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler.IL.Patterns; using ICSharpCode.Decompiler.IL.Patterns;
@ -70,6 +71,16 @@ namespace ICSharpCode.Decompiler.IL
// make sure to read the remarks on the ReplaceWith() method. // make sure to read the remarks on the ReplaceWith() method.
} }
internal static void DebugAssert([DoesNotReturnIf(false)] bool b)
{
Debug.Assert(b);
}
internal static void DebugAssert([DoesNotReturnIf(false)] bool b, string msg)
{
Debug.Assert(b, msg);
}
[Conditional("DEBUG")] [Conditional("DEBUG")]
internal virtual void CheckInvariant(ILPhase phase) internal virtual void CheckInvariant(ILPhase phase)
{ {
@ -494,7 +505,7 @@ namespace ICSharpCode.Decompiler.IL
internal ChildrenEnumerator(ILInstruction inst) internal ChildrenEnumerator(ILInstruction inst)
{ {
Debug.Assert(inst != null); DebugAssert(inst != null);
this.inst = inst; this.inst = inst;
this.pos = -1; this.pos = -1;
this.end = inst!.GetChildCount(); this.end = inst!.GetChildCount();
@ -951,7 +962,7 @@ namespace ICSharpCode.Decompiler.IL
public interface IInstructionWithMethodOperand public interface IInstructionWithMethodOperand
{ {
IMethod Method { get; } IMethod? Method { get; }
} }
public interface ILiftableInstruction public interface ILiftableInstruction

20
ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs

@ -96,7 +96,7 @@ namespace ICSharpCode.Decompiler.IL
public int NumPositionalPatterns { public int NumPositionalPatterns {
get { get {
if (IsDeconstructCall) if (IsDeconstructCall)
return method.Parameters.Count - (method.IsStatic ? 1 : 0); return method!.Parameters.Count - (method.IsStatic ? 1 : 0);
else if (IsDeconstructTuple) else if (IsDeconstructTuple)
return TupleType.GetTupleElementTypes(variable.Type).Length; return TupleType.GetTupleElementTypes(variable.Type).Length;
else else
@ -104,7 +104,7 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
public MatchInstruction(ILVariable variable, ILInstruction? testedOperand) public MatchInstruction(ILVariable variable, ILInstruction testedOperand)
: this(variable, method: null, testedOperand) : this(variable, method: null, testedOperand)
{ {
} }
@ -153,9 +153,9 @@ namespace ICSharpCode.Decompiler.IL
{ {
if (this.IsDeconstructCall) if (this.IsDeconstructCall)
{ {
int firstOutParam = (method.IsStatic ? 1 : 0); int firstOutParam = (method!.IsStatic ? 1 : 0);
var outParamType = this.Method.Parameters[firstOutParam + index].Type; var outParamType = method.Parameters[firstOutParam + index].Type;
if (!(outParamType is ByReferenceType brt)) if (outParamType is not ByReferenceType brt)
throw new InvalidOperationException("deconstruct out param must be by reference"); throw new InvalidOperationException("deconstruct out param must be by reference");
return brt.ElementType; return brt.ElementType;
} }
@ -210,8 +210,11 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal static bool IsDeconstructMethod(IMethod method) internal static bool IsDeconstructMethod(IMethod? method)
{ {
if (method == null
)
return false;
if (method.Name != "Deconstruct") if (method.Name != "Deconstruct")
return false; return false;
if (method.ReturnType.Kind != TypeKind.Void) if (method.ReturnType.Kind != TypeKind.Void)
@ -260,7 +263,10 @@ namespace ICSharpCode.Decompiler.IL
if (IsDeconstructCall) if (IsDeconstructCall)
{ {
output.Write(".deconstruct["); output.Write(".deconstruct[");
method.WriteTo(output); if (method == null)
output.Write("<null>");
else
method.WriteTo(output);
output.Write(']'); output.Write(']');
} }
if (IsDeconstructTuple) if (IsDeconstructTuple)

4
ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs

@ -26,14 +26,14 @@ namespace ICSharpCode.Decompiler.IL
{ {
public List<(string? Key, int Value)> Map { get; } public List<(string? Key, int Value)> Map { get; }
public StringToInt(ILInstruction? argument, List<(string? Key, int Value)> map) public StringToInt(ILInstruction argument, List<(string? Key, int Value)> map)
: base(OpCode.StringToInt) : base(OpCode.StringToInt)
{ {
this.Argument = argument; this.Argument = argument;
this.Map = map; this.Map = map;
} }
public StringToInt(ILInstruction? argument, string?[] map) public StringToInt(ILInstruction argument, string?[] map)
: this(argument, ArrayToDictionary(map)) : this(argument, ArrayToDictionary(map))
{ {
} }

8
ICSharpCode.Decompiler/Util/NullAttributes.cs

@ -25,5 +25,13 @@ namespace System.Diagnostics.CodeAnalysis
public bool ReturnValue { get; } public bool ReturnValue { get; }
} }
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class DoesNotReturnIfAttribute : Attribute
{
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
public bool ParameterValue { get; }
}
} }
#endif #endif

Loading…
Cancel
Save