Browse Source

#nullable enable for Instructions.tt

issue1638
Daniel Grunwald 4 years ago
parent
commit
245261a1e5
  1. 508
      ICSharpCode.Decompiler/IL/Instructions.cs
  2. 85
      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

85
ICSharpCode.Decompiler/IL/Instructions.tt

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
@ -32,7 +34,7 @@ @@ -32,7 +34,7 @@
AbstractBaseClass, CustomArguments(("left", null), ("right", null)), HasFlag("InstructionFlags.None")),
new OpCode("CallInstruction", "Instruction with a list of arguments.",
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("CompoundAssignmentInstruction", "Common instruction for compound assignments.",
AbstractBaseClass, CustomConstructor, CustomArguments(("target", null), ("value", null))),
@ -68,7 +70,7 @@ @@ -68,7 +70,7 @@
new ChildInfo("init") { CanInlineInto = true },
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.",
CustomClassName("BinaryNumericInstruction"), Binary, CustomWriteTo, CustomConstructor, CustomComputeFlags,
MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator && IsLifted == o.IsLifted")),
@ -215,11 +217,11 @@ @@ -215,11 +217,11 @@
new OpCode("ldnull", "Loads the null reference.",
CustomClassName("LdNull"), NoArguments, ResultType("O")),
new OpCode("ldftn", "Load method pointer",
CustomClassName("LdFtn"), NoArguments, HasMethodOperand, ResultType("I")),
CustomClassName("LdFtn"), NoArguments, HasMethodOperand(), ResultType("I")),
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",
CustomClassName("LdVirtDelegate"), Unary, HasTypeOperand, HasMethodOperand,
CustomClassName("LdVirtDelegate"), Unary, HasTypeOperand, HasMethodOperand(),
MayThrow, ResultType("O")),
new OpCode("ldtypetoken", "Loads runtime representation of metadata token",
CustomClassName("LdTypeToken"), NoArguments, HasTypeOperand, ResultType("O")),
@ -287,7 +289,7 @@ @@ -287,7 +289,7 @@
+ "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
+ "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).",
CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo, ResultType("I4")),
@ -297,7 +299,7 @@ @@ -297,7 +299,7 @@
new OpCode("user.logic.operator", "Use of user-defined &amp;&amp; or || operator.",
CustomClassName("UserDefinedLogicOperator"),
HasMethodOperand, ResultType("O"),
HasMethodOperand(), ResultType("O"),
CustomChildren(new []{
new ChildInfo("left") { CanInlineInto = true },
new ChildInfo("right") { CanInlineInto = false } // only executed depending on value of left
@ -337,7 +339,7 @@ @@ -337,7 +339,7 @@
CustomClassName("DynamicIsEventInstruction"), Dynamic, CustomArguments(("argument", new[] { "O" })), CustomWriteTo),
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"),
CustomChildren(new []{
new ChildInfo("testedOperand") { CanInlineInto = true },
@ -371,8 +373,8 @@ @@ -371,8 +373,8 @@
};
#>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
@ -437,7 +439,7 @@ namespace <#=opCode.Namespace#> @@ -437,7 +439,7 @@ namespace <#=opCode.Namespace#>
}
<# } #>
<# 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#>;
return <#=string.Join(" && ", opCode.PerformMatchConditions)#>;
@ -637,10 +639,15 @@ namespace ICSharpCode.Decompiler.IL @@ -637,10 +639,15 @@ namespace ICSharpCode.Decompiler.IL
public string TypeName;
public string Name;
public string FieldName;
public bool IsReferenceType = true;
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 @@ -866,7 +873,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.WriteArguments.Add("output.Write(\", \");");
opCode.WriteArguments.Add("this." + arg + ".WriteTo(output, options);");
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
+ "\tget { return this." + arg + "; }" + Environment.NewLine
+ "\tset {" + Environment.NewLine
@ -885,7 +892,7 @@ namespace ICSharpCode.Decompiler.IL @@ -885,7 +892,7 @@ namespace ICSharpCode.Decompiler.IL
checkString += " || ";
checkString += arg + ".ResultType == " + expectedTypeCode;
}
opCode.Invariants.Add("Debug.Assert(" + checkString + ");");
opCode.Invariants.Add("DebugAssert(" + checkString + ");");
}
}
opCode.WriteArguments.Add("output.Write(')');");
@ -1008,8 +1015,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1008,8 +1015,7 @@ namespace ICSharpCode.Decompiler.IL
Action<OpCode> action = opCode => {
opCode.ConstructorParameters.Add("ILVariable variable");
opCode.Members.Add("ILVariable variable;");
opCode.ConstructorBody.Add("Debug.Assert(variable != null);");
opCode.ConstructorBody.Add("this.variable = variable;");
opCode.ConstructorBody.Add("this.variable = variable ?? throw new ArgumentNullException(nameof(variable));");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILVariable", Name = "variable", FieldName = "Variable" });
opCode.PerformMatchConditions.Add("variable == o.variable");
opCode.GenerateWriteTo = true;
@ -1019,7 +1025,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1019,7 +1025,7 @@ namespace ICSharpCode.Decompiler.IL
opCode.Members.Add(@"public ILVariable Variable {
get { return variable; }
set {
Debug.Assert(value != null);
DebugAssert(value != null);
if (IsConnected)
variable.RemoveAccessInstruction(this);
variable = value;
@ -1048,8 +1054,8 @@ protected override void Disconnected() @@ -1048,8 +1054,8 @@ protected override void Disconnected()
}
".Replace("Access", accessType));
if (generateCheckInvariant) {
opCode.Invariants.Add("Debug.Assert(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 || this.IsDescendantOf(variable.Function!));");
opCode.Invariants.Add("DebugAssert(phase <= ILPhase.InILReader || variable.Function!.Variables[variable.IndexInFunction] == variable);");
}
};
if (accessType == "Load") {
@ -1093,22 +1099,26 @@ protected override void Disconnected() @@ -1093,22 +1099,26 @@ protected override void Disconnected()
opCode.WriteOperand.Add("type.WriteTo(output);");
};
static Action<OpCode> HasMethodOperand = opCode => {
opCode.ConstructorParameters.Add("IMethod method");
opCode.Members.Add("readonly IMethod method;");
opCode.ConstructorBody.Add("this.method = method;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IMethod", Name = "method", FieldName = "Method" });
opCode.PerformMatchConditions.Add("object.Equals(method, o.method)");
opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine
+ "public IMethod Method { get { return method; } }");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("if (method != null) {");
opCode.WriteOperand.Add("\toutput.Write(' ');");
opCode.WriteOperand.Add("\tmethod.WriteTo(output);");
opCode.WriteOperand.Add("}");
opCode.Interfaces.Add("IInstructionWithMethodOperand");
};
static Action<OpCode> HasMethodOperand(bool nullable = false)
{
return opCode => {
string n = nullable ? "?" : "";
opCode.ConstructorParameters.Add($"IMethod{n} method");
opCode.Members.Add($"readonly IMethod{n} method;");
opCode.ConstructorBody.Add("this.method = method;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = $"IMethod{n}", Name = "method", FieldName = "Method", IsReferenceType = !nullable });
opCode.PerformMatchConditions.Add("object.Equals(method, o.method)");
opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine
+ $"public IMethod{n} Method => method;");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("if (method != null) {");
opCode.WriteOperand.Add("\toutput.Write(' ');");
opCode.WriteOperand.Add("\tmethod.WriteTo(output);");
opCode.WriteOperand.Add("}");
opCode.Interfaces.Add("IInstructionWithMethodOperand");
};
}
static Action<OpCode> HasMemberOperand = opCode => {
opCode.ConstructorParameters.Add("IMember member");
opCode.Members.Add("readonly IMember member;");
@ -1139,7 +1149,12 @@ protected override void Disconnected() @@ -1139,7 +1149,12 @@ protected override void Disconnected()
return opCode => {
NoArguments(opCode);
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.Members.Add("public readonly " + operandType + " Value;");
opCode.ConstructorBody.Add("this.Value = value;");

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

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

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

@ -61,10 +61,10 @@ namespace ICSharpCode.Decompiler.IL @@ -61,10 +61,10 @@ namespace ICSharpCode.Decompiler.IL
void AdditionalInvariants()
{
var matchInst = FindMatch();
Debug.Assert(matchInst != null && (matchInst.IsDeconstructCall || matchInst.IsDeconstructTuple));
Debug.Assert(Argument.MatchLdLoc(matchInst!.Variable));
DebugAssert(matchInst != null && (matchInst.IsDeconstructCall || matchInst.IsDeconstructTuple));
DebugAssert(Argument.MatchLdLoc(matchInst.Variable));
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 @@ -145,7 +145,7 @@ namespace ICSharpCode.Decompiler.IL
public DynamicConvertInstruction(CSharpBinderFlags binderFlags, IType type, IType? context, ILInstruction argument)
: base(OpCode.DynamicConvertInstruction, binderFlags, context)
{
Type = type;
this.type = type;
Argument = argument;
}

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

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

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

@ -21,6 +21,7 @@ @@ -21,6 +21,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using ICSharpCode.Decompiler.IL.Patterns;
@ -70,6 +71,16 @@ namespace ICSharpCode.Decompiler.IL @@ -70,6 +71,16 @@ namespace ICSharpCode.Decompiler.IL
// 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")]
internal virtual void CheckInvariant(ILPhase phase)
{
@ -494,7 +505,7 @@ namespace ICSharpCode.Decompiler.IL @@ -494,7 +505,7 @@ namespace ICSharpCode.Decompiler.IL
internal ChildrenEnumerator(ILInstruction inst)
{
Debug.Assert(inst != null);
DebugAssert(inst != null);
this.inst = inst;
this.pos = -1;
this.end = inst!.GetChildCount();
@ -951,7 +962,7 @@ namespace ICSharpCode.Decompiler.IL @@ -951,7 +962,7 @@ namespace ICSharpCode.Decompiler.IL
public interface IInstructionWithMethodOperand
{
IMethod Method { get; }
IMethod? Method { get; }
}
public interface ILiftableInstruction

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

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

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

@ -26,14 +26,14 @@ namespace ICSharpCode.Decompiler.IL @@ -26,14 +26,14 @@ namespace ICSharpCode.Decompiler.IL
{
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)
{
this.Argument = argument;
this.Map = map;
}
public StringToInt(ILInstruction? argument, string?[] map)
public StringToInt(ILInstruction argument, string?[] map)
: this(argument, ArrayToDictionary(map))
{
}

8
ICSharpCode.Decompiler/Util/NullAttributes.cs

@ -25,5 +25,13 @@ namespace System.Diagnostics.CodeAnalysis @@ -25,5 +25,13 @@ namespace System.Diagnostics.CodeAnalysis
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

Loading…
Cancel
Save