diff --git a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs index a2a7dec3b..6327b1634 100644 --- a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs @@ -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 readonly bool isInheritedRecord; readonly bool isStruct; readonly bool isSealed; - readonly IMethod primaryCtor; - readonly IType baseClass; + readonly IMethod? primaryCtor; + readonly IType? baseClass; readonly Dictionary backingFieldToAutoProperty = new Dictionary(); readonly Dictionary autoPropertyToBackingField = new Dictionary(); readonly Dictionary primaryCtorParameterToAutoProperty = new Dictionary(); @@ -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 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 } } - 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 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 } } - IMethod DetectPrimaryConstructor() + IMethod? DetectPrimaryConstructor() { Debug.Assert(recordTypeDef.IsRecord); if (!settings.UsePrimaryConstructorSyntax) @@ -168,14 +171,14 @@ namespace ICSharpCode.Decompiler.CSharp var subst = recordTypeDef.AsParameterizedType().GetSubstitution(); Dictionary nameToMemberMap = new Dictionary(StringComparer.Ordinal); - Dictionary ctorChainMap = new Dictionary(); + Dictionary ctorChainMap = new Dictionary(); 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 { 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 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 { 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 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 /// /// Gets the detected primary constructor. Returns null, if there was no primary constructor detected. /// - public IMethod PrimaryConstructor => primaryCtor; + public IMethod? PrimaryConstructor => primaryCtor; public bool IsInheritedRecord => isInheritedRecord; @@ -472,9 +475,9 @@ namespace ICSharpCode.Decompiler.CSharp && autoPropertyToPrimaryCtorParameter.ContainsKey((IProperty)property.Specialize(subst)); } - internal Dictionary GetParameterToBackingStoreMap() + internal Dictionary GetParameterToBackingStoreMap() { - var result = new Dictionary(); + var result = new Dictionary(); foreach (var (parameter, property) in primaryCtorParameterToAutoProperty) { result.Add(parameter, (property, autoPropertyToBackingField[property])); @@ -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 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 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 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 } } - 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 { 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 } } - 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 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 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 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 } } - Block DecompileBody(IMethod method) + Block? DecompileBody(IMethod method) { if (method == null || method.MetadataToken.IsNil) return null;