Browse Source

RecordDecompiler: nullable enable

pull/3622/head
Siegfried Pammer 1 month ago
parent
commit
2bb06709e9
  1. 65
      ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs

65
ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs

@ -16,9 +16,12 @@ @@ -16,9 +16,12 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection.Metadata;
using System.Threading;
@ -40,8 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -40,8 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp
readonly bool isInheritedRecord;
readonly bool isStruct;
readonly bool isSealed;
readonly IMethod primaryCtor;
readonly IType baseClass;
readonly IMethod? primaryCtor;
readonly IType? baseClass;
readonly Dictionary<IField, IProperty> backingFieldToAutoProperty = new Dictionary<IField, IProperty>();
readonly Dictionary<IProperty, IField> autoPropertyToBackingField = new Dictionary<IProperty, IField>();
readonly Dictionary<IParameter, IProperty> primaryCtorParameterToAutoProperty = new Dictionary<IParameter, IProperty>();
@ -76,7 +79,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -76,7 +79,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
bool IsAutoProperty(IProperty p, out IField field)
bool IsAutoProperty(IProperty p, [NotNullWhen(true)] out IField? field)
{
field = null;
if (p.IsStatic)
@ -109,7 +112,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -109,7 +112,7 @@ namespace ICSharpCode.Decompiler.CSharp
return field.Name == $"<{p.Name}>k__BackingField";
}
bool IsAutoGetter(IMethod method, out IField field)
bool IsAutoGetter(IMethod method, [NotNullWhen(true)] out IField? field)
{
field = null;
var body = DecompileBody(method);
@ -130,7 +133,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -130,7 +133,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
bool IsAutoSetter(IMethod method, out IField field)
bool IsAutoSetter(IMethod method, [NotNullWhen(true)] out IField? field)
{
field = null;
Debug.Assert(!method.IsStatic);
@ -138,7 +141,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -138,7 +141,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (body == null)
return false;
// this.field = value;
ILInstruction valueInst;
ILInstruction? valueInst;
if (method.IsStatic)
{
if (!body.Instructions[0].MatchStsFld(out field, out valueInst))
@ -159,7 +162,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -159,7 +162,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
IMethod DetectPrimaryConstructor()
IMethod? DetectPrimaryConstructor()
{
Debug.Assert(recordTypeDef.IsRecord);
if (!settings.UsePrimaryConstructorSyntax)
@ -168,14 +171,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -168,14 +171,14 @@ namespace ICSharpCode.Decompiler.CSharp
var subst = recordTypeDef.AsParameterizedType().GetSubstitution();
Dictionary<string, IMember> nameToMemberMap = new Dictionary<string, IMember>(StringComparer.Ordinal);
Dictionary<IMethod, IMethod> ctorChainMap = new Dictionary<IMethod, IMethod>();
Dictionary<IMethod, IMethod?> ctorChainMap = new Dictionary<IMethod, IMethod?>();
foreach (IMember m in recordTypeDef.GetMembers(m => m.SymbolKind is SymbolKind.Property or SymbolKind.Field, GetMemberOptions.ReturnMemberDefinitions))
{
nameToMemberMap[m.Name] = m;
}
IMethod guessedPrimaryCtor = null;
IMethod? guessedPrimaryCtor = null;
foreach (var method in recordTypeDef.Methods)
{
@ -191,10 +194,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -191,10 +194,10 @@ namespace ICSharpCode.Decompiler.CSharp
{
continue;
}
IMethod chainedCtor = (IMethod)FindChainedCtor(body)?.MemberDefinition;
IMethod? chainedCtor = (IMethod?)FindChainedCtor(body)?.MemberDefinition;
ctorChainMap[method] = chainedCtor;
if (chainedCtor != null && chainedCtor.DeclaringTypeDefinition.Equals(recordTypeDef))
if (chainedCtor != null && chainedCtor.DeclaringTypeDefinition!.Equals(recordTypeDef))
{
continue;
}
@ -242,7 +245,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -242,7 +245,7 @@ namespace ICSharpCode.Decompiler.CSharp
foreach (var (parameter, property) in primaryCtorParameterToAutoProperty.ToArray())
{
if (!parameter.Owner.Equals(guessedPrimaryCtor))
if (!parameter.Owner!.Equals(guessedPrimaryCtor))
{
primaryCtorParameterToAutoProperty.Remove(parameter);
}
@ -302,13 +305,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -302,13 +305,13 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (v.Kind != VariableKind.Parameter || v.Index < parameterIndex)
return false;
parameterIndex = v.Index.Value;
parameterIndex = v.Index!.Value;
}
else if (valueInst.MatchLdObj(out valueInst, out _) && valueInst.MatchLdLoc(out v))
{
if (v.Kind != VariableKind.Parameter || v.Index < parameterIndex)
return false;
parameterIndex = v.Index.Value;
parameterIndex = v.Index!.Value;
if (method.Parameters[parameterIndex].ReferenceKind is ReferenceKind.None)
{
return false;
@ -338,7 +341,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -338,7 +341,7 @@ namespace ICSharpCode.Decompiler.CSharp
return returnInst != null && returnInst.MatchReturn(out var retVal) && retVal.MatchNop();
}
IMethod FindChainedCtor(Block body)
IMethod? FindChainedCtor(Block body)
{
// look for a call instruction or assignment to a chained constructor
foreach (var inst in body.Instructions)
@ -379,7 +382,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -379,7 +382,7 @@ namespace ICSharpCode.Decompiler.CSharp
/// <summary>
/// Gets the detected primary constructor. Returns null, if there was no primary constructor detected.
/// </summary>
public IMethod PrimaryConstructor => primaryCtor;
public IMethod? PrimaryConstructor => primaryCtor;
public bool IsInheritedRecord => isInheritedRecord;
@ -472,9 +475,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -472,9 +475,9 @@ namespace ICSharpCode.Decompiler.CSharp
&& autoPropertyToPrimaryCtorParameter.ContainsKey((IProperty)property.Specialize(subst));
}
internal Dictionary<IParameter, (IProperty, IField)> GetParameterToBackingStoreMap()
internal Dictionary<IParameter, (IProperty?, IField)> GetParameterToBackingStoreMap()
{
var result = new Dictionary<IParameter, (IProperty, IField)>();
var result = new Dictionary<IParameter, (IProperty?, IField)>();
foreach (var (parameter, property) in primaryCtorParameterToAutoProperty)
{
result.Add(parameter, (property, autoPropertyToBackingField[property]));
@ -549,7 +552,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -549,7 +552,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (!(member is IField field))
{
if (!autoPropertyToBackingField.TryGetValue((IProperty)member, out field))
if (!autoPropertyToBackingField.TryGetValue((IProperty)member, out field!))
continue;
}
if (pos >= body.Instructions.Count)
@ -668,7 +671,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -668,7 +671,7 @@ namespace ICSharpCode.Decompiler.CSharp
trueInst = Block.Unwrap(trueInst);
if (!MatchStringBuilderAppend(trueInst, builder, out var val))
return false;
if (!(val.MatchLdStr(out string text) && text == ", "))
if (!(val.MatchLdStr(out string? text) && text == ", "))
return false;
pos++;
@ -700,7 +703,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -700,7 +703,7 @@ namespace ICSharpCode.Decompiler.CSharp
callvirt Append(ldloc builder, ldstr " = ")
callvirt Append(ldloc builder, constrained[System.Int32].callvirt ToString(ldflda B(ldloc this)))
leave IL_0000 (ldc.i4 1) */
if (!MatchStringBuilderAppendConstant(out string text))
if (!MatchStringBuilderAppendConstant(out string? text))
return false;
string expectedText = (needsComma ? ", " : "") + member.Name + " = ";
if (text != expectedText)
@ -775,10 +778,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -775,10 +778,10 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
}
bool MatchStringBuilderAppendConstant(out string text)
bool MatchStringBuilderAppendConstant([NotNullWhen(true)] out string? text)
{
text = null;
while (MatchStringBuilderAppend(body.Instructions[pos], builder, out var val) && val.MatchLdStr(out string valText))
while (MatchStringBuilderAppend(body.Instructions[pos], builder, out var val) && val.MatchLdStr(out string? valText))
{
text += valText;
pos++;
@ -787,7 +790,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -787,7 +790,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
private bool MatchStringBuilderAppend(ILInstruction inst, ILVariable sb, out ILInstruction val)
private bool MatchStringBuilderAppend(ILInstruction inst, ILVariable sb, [NotNullWhen(true)] out ILInstruction? val)
{
val = null;
if (!(inst is CallVirt { Method: { Name: "Append", DeclaringType: { Namespace: "System.Text", Name: "StringBuilder" } } } call))
@ -863,7 +866,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -863,7 +866,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
return val != null && val.Length == 1 && call.Arguments[1].MatchLdcI4(val[0]);
}
return call.Arguments[1].MatchLdStr(out string val1) && val1 == val;
return call.Arguments[1].MatchLdStr(out string? val1) && val1 == val;
}
}
@ -1015,7 +1018,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1015,7 +1018,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
private bool MatchGetEqualityContract(ILInstruction inst, out ILInstruction target)
private bool MatchGetEqualityContract(ILInstruction inst, [NotNullWhen(true)] out ILInstruction? target)
{
target = null;
if (!(inst is CallInstruction { Method: { Name: "get_EqualityContract" } } call))
@ -1149,7 +1152,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1149,7 +1152,7 @@ namespace ICSharpCode.Decompiler.CSharp
bool IsGeneratedDeconstruct(IMethod method)
{
Debug.Assert(method.Name == "Deconstruct" && method.Parameters.Count == primaryCtor.Parameters.Count);
Debug.Assert(method.Name == "Deconstruct" && method.Parameters.Count == primaryCtor?.Parameters.Count);
if (!method.ReturnType.IsKnownType(KnownTypeCode.Void))
return false;
@ -1205,7 +1208,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1205,7 +1208,7 @@ namespace ICSharpCode.Decompiler.CSharp
return returnInst != null && returnInst.MatchReturn(out var retVal) && retVal.MatchNop();
}
bool MatchMemberAccess(ILInstruction inst, out ILInstruction target, out IMember member)
bool MatchMemberAccess(ILInstruction inst, [NotNullWhen(true)] out ILInstruction? target, [NotNullWhen(true)] out IMember? member)
{
target = null;
member = null;
@ -1222,9 +1225,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1222,9 +1225,9 @@ namespace ICSharpCode.Decompiler.CSharp
member = property;
return true;
}
else if (inst.MatchLdFld(out target, out IField field))
else if (inst.MatchLdFld(out target, out IField? field))
{
if (backingFieldToAutoProperty.TryGetValue(field, out property))
if (backingFieldToAutoProperty.TryGetValue(field, out property!))
member = property;
else
member = field;
@ -1236,7 +1239,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1236,7 +1239,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
Block DecompileBody(IMethod method)
Block? DecompileBody(IMethod method)
{
if (method == null || method.MetadataToken.IsNil)
return null;

Loading…
Cancel
Save