summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/ModLoading
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-04-13 20:24:14 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-04-13 20:24:14 -0400
commitf39da383a17b368e92fd243cf155b27ba42671f3 (patch)
tree56c215dfb34da270a7714afd141e76a94c69a2c0 /src/SMAPI/Framework/ModLoading
parent6e9e8aef1ef97e1a4ef4410ce300cb1c47eca986 (diff)
downloadSMAPI-f39da383a17b368e92fd243cf155b27ba42671f3.tar.gz
SMAPI-f39da383a17b368e92fd243cf155b27ba42671f3.tar.bz2
SMAPI-f39da383a17b368e92fd243cf155b27ba42671f3.zip
enable nullable annotations in SMAPI where no logic changes are needed (#837)
Diffstat (limited to 'src/SMAPI/Framework/ModLoading')
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs8
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs4
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs4
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs4
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs4
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs15
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs13
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs6
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs8
-rw-r--r--src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs4
-rw-r--r--src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs25
-rw-r--r--src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs10
-rw-r--r--src/SMAPI/Framework/ModLoading/InvalidModStateException.cs4
-rw-r--r--src/SMAPI/Framework/ModLoading/ModMetadata.cs38
-rw-r--r--src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs6
-rw-r--r--src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs9
-rw-r--r--src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs6
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs16
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs19
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs15
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs13
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs6
-rw-r--r--src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs6
-rw-r--r--src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs14
24 files changed, 112 insertions, 145 deletions
diff --git a/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs b/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs
index 1d4ddf72..b3378ad1 100644
--- a/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs
+++ b/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System.Collections.Generic;
using Mono.Cecil;
@@ -38,6 +36,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <summary>Resolve an assembly reference.</summary>
/// <param name="name">The assembly name.</param>
+ /// <exception cref="AssemblyResolutionException">The assembly can't be resolved.</exception>
public override AssemblyDefinition Resolve(AssemblyNameReference name)
{
return this.ResolveName(name.Name) ?? base.Resolve(name);
@@ -46,6 +45,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <summary>Resolve an assembly reference.</summary>
/// <param name="name">The assembly name.</param>
/// <param name="parameters">The assembly reader parameters.</param>
+ /// <exception cref="AssemblyResolutionException">The assembly can't be resolved.</exception>
public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
return this.ResolveName(name.Name) ?? base.Resolve(name, parameters);
@@ -57,9 +57,9 @@ namespace StardewModdingAPI.Framework.ModLoading
*********/
/// <summary>Resolve a known assembly definition based on its short or full name.</summary>
/// <param name="name">The assembly's short or full name.</param>
- private AssemblyDefinition ResolveName(string name)
+ private AssemblyDefinition? ResolveName(string name)
{
- return this.Lookup.TryGetValue(name, out AssemblyDefinition match)
+ return this.Lookup.TryGetValue(name, out AssemblyDefinition? match)
? match
: null;
}
diff --git a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs
index 7c94beb7..f5d449c5 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
@@ -57,7 +55,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
{
if (this.MethodNames.Any())
{
- MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ MethodReference? methodRef = RewriteHelper.AsMethodReference(instruction);
if (methodRef != null && methodRef.DeclaringType.FullName == this.FullTypeName && this.MethodNames.Contains(methodRef.Name))
{
string eventName = methodRef.Name.Split(new[] { '_' }, 2)[1];
diff --git a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs
index 96b4098a..7fe4abec 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
@@ -51,7 +49,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
{
if (this.FieldNames.Any())
{
- FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
+ FieldReference? fieldRef = RewriteHelper.AsFieldReference(instruction);
if (fieldRef != null && fieldRef.DeclaringType.FullName == this.FullTypeName && this.FieldNames.Contains(fieldRef.Name))
{
this.FieldNames.Remove(fieldRef.Name);
diff --git a/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs
index 7d3c1fd7..e8fdc8c7 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.ModLoading.Framework;
@@ -54,7 +52,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/// <param name="instruction">The IL instruction.</param>
protected bool IsMatch(Instruction instruction)
{
- MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ MethodReference? methodRef = RewriteHelper.AsMethodReference(instruction);
return
methodRef != null
&& methodRef.DeclaringType.FullName == this.FullTypeName
diff --git a/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs
index b2f2e193..2af76f55 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.ModLoading.Framework;
@@ -54,7 +52,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/// <param name="instruction">The IL instruction.</param>
protected bool IsMatch(Instruction instruction)
{
- MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ MethodReference? methodRef = RewriteHelper.AsMethodReference(instruction);
return
methodRef != null
&& methodRef.DeclaringType.FullName == this.FullTypeName
diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
index 81f90498..f34542c3 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
@@ -1,6 +1,5 @@
-#nullable disable
-
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -34,11 +33,11 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
{
// field reference
- FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
+ FieldReference? fieldRef = RewriteHelper.AsFieldReference(instruction);
if (fieldRef != null && this.ShouldValidate(fieldRef.DeclaringType))
{
// get target field
- FieldDefinition targetField = fieldRef.DeclaringType.Resolve()?.Fields.FirstOrDefault(p => p.Name == fieldRef.Name);
+ FieldDefinition? targetField = fieldRef.DeclaringType.Resolve()?.Fields.FirstOrDefault(p => p.Name == fieldRef.Name);
if (targetField == null)
return false;
@@ -51,16 +50,16 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
}
// method reference
- MethodReference methodReference = RewriteHelper.AsMethodReference(instruction);
+ MethodReference? methodReference = RewriteHelper.AsMethodReference(instruction);
if (methodReference != null && !this.IsUnsupported(methodReference) && this.ShouldValidate(methodReference.DeclaringType))
{
// get potential targets
- MethodDefinition[] candidateMethods = methodReference.DeclaringType.Resolve()?.Methods.Where(found => found.Name == methodReference.Name).ToArray();
+ MethodDefinition[]? candidateMethods = methodReference.DeclaringType.Resolve()?.Methods.Where(found => found.Name == methodReference.Name).ToArray();
if (candidateMethods == null || !candidateMethods.Any())
return false;
// compare return types
- MethodDefinition methodDef = methodReference.Resolve();
+ MethodDefinition? methodDef = methodReference.Resolve();
if (methodDef == null)
return false; // validated by ReferenceToMissingMemberFinder
@@ -80,7 +79,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
*********/
/// <summary>Whether references to the given type should be validated.</summary>
/// <param name="type">The type reference.</param>
- private bool ShouldValidate(TypeReference type)
+ private bool ShouldValidate([NotNullWhen(true)] TypeReference? type)
{
return type != null && this.ValidateReferencesToAssemblies.Contains(type.Scope.Name);
}
diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
index 001d1986..fae7fb12 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
@@ -1,6 +1,5 @@
-#nullable disable
-
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.ModLoading.Framework;
@@ -33,10 +32,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
{
// field reference
- FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
+ FieldReference? fieldRef = RewriteHelper.AsFieldReference(instruction);
if (fieldRef != null && this.ShouldValidate(fieldRef.DeclaringType))
{
- FieldDefinition target = fieldRef.Resolve();
+ FieldDefinition? target = fieldRef.Resolve();
if (target == null || target.HasConstant)
{
this.MarkFlag(InstructionHandleResult.NotCompatible, $"reference to {fieldRef.DeclaringType.FullName}.{fieldRef.Name} (no such field)");
@@ -45,10 +44,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
}
// method reference
- MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ MethodReference? methodRef = RewriteHelper.AsMethodReference(instruction);
if (methodRef != null && this.ShouldValidate(methodRef.DeclaringType) && !this.IsUnsupported(methodRef))
{
- MethodDefinition target = methodRef.Resolve();
+ MethodDefinition? target = methodRef.Resolve();
if (target == null)
{
string phrase;
@@ -73,7 +72,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
*********/
/// <summary>Whether references to the given type should be validated.</summary>
/// <param name="type">The type reference.</param>
- private bool ShouldValidate(TypeReference type)
+ private bool ShouldValidate([NotNullWhen(true)] TypeReference? type)
{
return type != null && this.ValidateReferencesToAssemblies.Contains(type.Scope.Name);
}
diff --git a/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs
index 4c589ed8..17acbf9a 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using Mono.Cecil;
using StardewModdingAPI.Framework.ModLoading.Framework;
@@ -19,7 +17,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
private readonly InstructionHandleResult Result;
/// <summary>Get whether a matched type should be ignored.</summary>
- private readonly Func<TypeReference, bool> ShouldIgnore;
+ private readonly Func<TypeReference, bool>? ShouldIgnore;
/*********
@@ -29,7 +27,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/// <param name="assemblyName">The full assembly name to which to find references.</param>
/// <param name="result">The result to return for matching instructions.</param>
/// <param name="shouldIgnore">Get whether a matched type should be ignored.</param>
- public TypeAssemblyFinder(string assemblyName, InstructionHandleResult result, Func<TypeReference, bool> shouldIgnore = null)
+ public TypeAssemblyFinder(string assemblyName, InstructionHandleResult result, Func<TypeReference, bool>? shouldIgnore = null)
: base(defaultPhrase: $"{assemblyName} assembly")
{
this.AssemblyName = assemblyName;
diff --git a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs
index 04a5b970..77762f41 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using Mono.Cecil;
@@ -20,7 +18,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
private readonly InstructionHandleResult Result;
/// <summary>Get whether a matched type should be ignored.</summary>
- private readonly Func<TypeReference, bool> ShouldIgnore;
+ private readonly Func<TypeReference, bool>? ShouldIgnore;
/*********
@@ -30,7 +28,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/// <param name="fullTypeNames">The full type names to match.</param>
/// <param name="result">The result to return for matching instructions.</param>
/// <param name="shouldIgnore">Get whether a matched type should be ignored.</param>
- public TypeFinder(string[] fullTypeNames, InstructionHandleResult result, Func<TypeReference, bool> shouldIgnore = null)
+ public TypeFinder(string[] fullTypeNames, InstructionHandleResult result, Func<TypeReference, bool>? shouldIgnore = null)
: base(defaultPhrase: $"{string.Join(", ", fullTypeNames)} type{(fullTypeNames.Length != 1 ? "s" : "")}") // default phrase should never be used
{
this.FullTypeNames = new HashSet<string>(fullTypeNames);
@@ -42,7 +40,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/// <param name="fullTypeName">The full type name to match.</param>
/// <param name="result">The result to return for matching instructions.</param>
/// <param name="shouldIgnore">Get whether a matched type should be ignored.</param>
- public TypeFinder(string fullTypeName, InstructionHandleResult result, Func<TypeReference, bool> shouldIgnore = null)
+ public TypeFinder(string fullTypeName, InstructionHandleResult result, Func<TypeReference, bool>? shouldIgnore = null)
: this(new[] { fullTypeName }, result, shouldIgnore) { }
/// <inheritdoc />
diff --git a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs
index bea786cd..865bf076 100644
--- a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs
+++ b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using Mono.Cecil;
@@ -59,7 +57,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
/// <param name="flag">The result flag to set.</param>
/// <param name="resultMessage">The result message to add.</param>
/// <returns>Returns true for convenience.</returns>
- protected bool MarkFlag(InstructionHandleResult flag, string resultMessage = null)
+ protected bool MarkFlag(InstructionHandleResult flag, string? resultMessage = null)
{
this.Flags.Add(flag);
if (resultMessage != null)
diff --git a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs
index 09ff78f7..55369602 100644
--- a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs
@@ -1,7 +1,6 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -10,6 +9,7 @@ using Mono.Collections.Generic;
namespace StardewModdingAPI.Framework.ModLoading.Framework
{
/// <summary>Handles recursively rewriting loaded assembly code.</summary>
+ [SuppressMessage("ReSharper", "AccessToModifiedClosure", Justification = "Rewrite callbacks are invoked immediately.")]
internal class RecursiveRewriter
{
/*********
@@ -77,7 +77,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
{
changed |= this.RewriteModuleImpl(this.Module);
- foreach (var type in types)
+ foreach (TypeDefinition type in types)
changed |= this.RewriteTypeDefinition(type);
}
catch (Exception ex)
@@ -129,9 +129,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
ILProcessor cil = method.Body.GetILProcessor();
Collection<Instruction> instructions = cil.Body.Instructions;
bool addedInstructions = false;
+ // ReSharper disable once ForCanBeConvertedToForeach -- deliberate to allow changing the collection
for (int i = 0; i < instructions.Count; i++)
{
- var instruction = instructions[i];
+ Instruction instruction = instructions[i];
if (instruction.OpCode.Code == Code.Nop)
continue;
@@ -174,7 +175,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
bool rewritten = false;
// field reference
- FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
+ FieldReference? fieldRef = RewriteHelper.AsFieldReference(instruction);
if (fieldRef != null)
{
rewritten |= this.RewriteTypeReference(fieldRef.DeclaringType, newType => fieldRef.DeclaringType = newType);
@@ -182,7 +183,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
}
// method reference
- MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ MethodReference? methodRef = RewriteHelper.AsMethodReference(instruction);
if (methodRef != null)
this.RewriteMethodReference(methodRef);
@@ -212,7 +213,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
});
rewritten |= this.RewriteTypeReference(methodRef.ReturnType, newType => methodRef.ReturnType = newType);
- foreach (var parameter in methodRef.Parameters)
+ foreach (ParameterDefinition parameter in methodRef.Parameters)
rewritten |= this.RewriteTypeReference(parameter.ParameterType, newType => parameter.ParameterType = newType);
if (methodRef is GenericInstanceMethod genericRef)
@@ -264,7 +265,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
bool curChanged = false;
// attribute type
- TypeReference newAttrType = null;
+ TypeReference? newAttrType = null;
rewritten |= this.RewriteTypeReference(attribute.AttributeType, newType =>
{
newAttrType = newType;
@@ -289,9 +290,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
if (curChanged)
{
// get constructor
- MethodDefinition constructor = (newAttrType ?? attribute.AttributeType)
+ MethodDefinition? constructor = (newAttrType ?? attribute.AttributeType)
.Resolve()
- .Methods
+ ?.Methods
.Where(method => method.IsConstructor)
.FirstOrDefault(ctor => RewriteHelper.HasMatchingSignature(ctor, attribute.Constructor));
if (constructor == null)
@@ -301,9 +302,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
var newAttr = new CustomAttribute(this.Module.ImportReference(constructor));
for (int i = 0; i < argTypes.Length; i++)
newAttr.ConstructorArguments.Add(new CustomAttributeArgument(argTypes[i], attribute.ConstructorArguments[i].Value));
- foreach (var prop in attribute.Properties)
+ foreach (CustomAttributeNamedArgument prop in attribute.Properties)
newAttr.Properties.Add(new CustomAttributeNamedArgument(prop.Name, prop.Argument));
- foreach (var field in attribute.Fields)
+ foreach (CustomAttributeNamedArgument field in attribute.Fields)
newAttr.Fields.Add(new CustomAttributeNamedArgument(field.Name, field.Argument));
// swap attribute
diff --git a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs
index 8f47fbdd..15f71251 100644
--- a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs
+++ b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Linq;
using System.Reflection;
@@ -23,7 +21,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
*********/
/// <summary>Get the field reference from an instruction if it matches.</summary>
/// <param name="instruction">The IL instruction.</param>
- public static FieldReference AsFieldReference(Instruction instruction)
+ public static FieldReference? AsFieldReference(Instruction instruction)
{
return instruction.OpCode == OpCodes.Ldfld || instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld
? (FieldReference)instruction.Operand
@@ -32,7 +30,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
/// <summary>Get the method reference from an instruction if it matches.</summary>
/// <param name="instruction">The IL instruction.</param>
- public static MethodReference AsMethodReference(Instruction instruction)
+ public static MethodReference? AsMethodReference(Instruction instruction)
{
return instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt || instruction.OpCode == OpCodes.Newobj
? (MethodReference)instruction.Operand
@@ -42,7 +40,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
/// <summary>Get the CIL instruction to load a value onto the stack.</summary>
/// <param name="rawValue">The constant value to inject.</param>
/// <returns>Returns the instruction, or <c>null</c> if the value type isn't supported.</returns>
- public static Instruction GetLoadValueInstruction(object rawValue)
+ public static Instruction? GetLoadValueInstruction(object? rawValue)
{
return rawValue switch
{
@@ -151,7 +149,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
/// <param name="typeA">The type ID to compare.</param>
/// <param name="typeB">The other type ID to compare.</param>
/// <returns>true if the type IDs look like the same type, false if not.</returns>
- public static bool LooksLikeSameType(TypeReference typeA, TypeReference typeB)
+ public static bool LooksLikeSameType(TypeReference? typeA, TypeReference? typeB)
{
return RewriteHelper.TypeDefinitionComparer.Equals(typeA, typeB);
}
diff --git a/src/SMAPI/Framework/ModLoading/InvalidModStateException.cs b/src/SMAPI/Framework/ModLoading/InvalidModStateException.cs
index 9dca9bc4..b53a9886 100644
--- a/src/SMAPI/Framework/ModLoading/InvalidModStateException.cs
+++ b/src/SMAPI/Framework/ModLoading/InvalidModStateException.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
namespace StardewModdingAPI.Framework.ModLoading
@@ -10,7 +8,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <summary>Construct an instance.</summary>
/// <param name="message">The error message.</param>
/// <param name="ex">The underlying exception, if any.</param>
- public InvalidModStateException(string message, Exception ex = null)
+ public InvalidModStateException(string message, Exception? ex = null)
: base(message, ex) { }
}
}
diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs
index 0e698bfd..fe54634b 100644
--- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs
+++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs
@@ -1,7 +1,6 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using StardewModdingAPI.Framework.ModHelpers;
@@ -44,7 +43,7 @@ namespace StardewModdingAPI.Framework.ModLoading
public IManifest Manifest { get; }
/// <inheritdoc />
- public ModDataRecordVersionedFields DataRecord { get; }
+ public ModDataRecordVersionedFields? DataRecord { get; }
/// <inheritdoc />
public ModMetadataStatus Status { get; private set; }
@@ -56,33 +55,35 @@ namespace StardewModdingAPI.Framework.ModLoading
public ModWarning Warnings => this.ActualWarnings & ~(this.DataRecord?.DataRecord.SuppressWarnings ?? ModWarning.None);
/// <inheritdoc />
- public string Error { get; private set; }
+ public string? Error { get; private set; }
/// <inheritdoc />
- public string ErrorDetails { get; private set; }
+ public string? ErrorDetails { get; private set; }
/// <inheritdoc />
public bool IsIgnored { get; }
/// <inheritdoc />
- public IMod Mod { get; private set; }
+ public IMod? Mod { get; private set; }
/// <inheritdoc />
- public IContentPack ContentPack { get; private set; }
+ public IContentPack? ContentPack { get; private set; }
/// <inheritdoc />
- public TranslationHelper Translations { get; private set; }
+ public TranslationHelper? Translations { get; private set; }
/// <inheritdoc />
- public IMonitor Monitor { get; private set; }
+ public IMonitor? Monitor { get; private set; }
/// <inheritdoc />
- public object Api { get; private set; }
+ public object? Api { get; private set; }
/// <inheritdoc />
- public ModEntryModel UpdateCheckData { get; private set; }
+ public ModEntryModel? UpdateCheckData { get; private set; }
/// <inheritdoc />
+ [MemberNotNullWhen(true, nameof(ModMetadata.ContentPack))]
+ [SuppressMessage("ReSharper", "ConstantConditionalAccessQualifier", Justification = "The manifest may be null for broken mods while loading.")]
public bool IsContentPack => this.Manifest?.ContentPackFor != null;
/// <summary>The fake content packs created by this mod, if any.</summary>
@@ -99,13 +100,13 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <param name="manifest">The mod manifest.</param>
/// <param name="dataRecord">Metadata about the mod from SMAPI's internal data (if any).</param>
/// <param name="isIgnored">Whether the mod folder should be ignored. This should be <c>true</c> if it was found within a folder whose name starts with a dot.</param>
- public ModMetadata(string displayName, string directoryPath, string rootPath, IManifest manifest, ModDataRecordVersionedFields dataRecord, bool isIgnored)
+ public ModMetadata(string displayName, string directoryPath, string rootPath, IManifest? manifest, ModDataRecordVersionedFields? dataRecord, bool isIgnored)
{
this.DisplayName = displayName;
this.DirectoryPath = directoryPath;
this.RootPath = rootPath;
this.RelativeDirectoryPath = PathUtilities.GetRelativePath(this.RootPath, this.DirectoryPath);
- this.Manifest = manifest;
+ this.Manifest = manifest!; // manifest may be null in low-level SMAPI code, but won't be null once it's received by mods via IModInfo
this.DataRecord = dataRecord;
this.IsIgnored = isIgnored;
@@ -121,7 +122,7 @@ namespace StardewModdingAPI.Framework.ModLoading
}
/// <inheritdoc />
- public IModMetadata SetStatus(ModMetadataStatus status, ModFailReason reason, string error, string errorDetails = null)
+ public IModMetadata SetStatus(ModMetadataStatus status, ModFailReason reason, string? error, string? errorDetails = null)
{
this.Status = status;
this.FailReason = reason;
@@ -162,7 +163,7 @@ namespace StardewModdingAPI.Framework.ModLoading
}
/// <inheritdoc />
- public IModMetadata SetApi(object api)
+ public IModMetadata SetApi(object? api)
{
this.Api = api;
return this;
@@ -176,6 +177,7 @@ namespace StardewModdingAPI.Framework.ModLoading
}
/// <inheritdoc />
+ [MemberNotNullWhen(true, nameof(IModInfo.Manifest))]
public bool HasManifest()
{
return this.Manifest != null;
@@ -190,7 +192,7 @@ namespace StardewModdingAPI.Framework.ModLoading
}
/// <inheritdoc />
- public bool HasID(string id)
+ public bool HasID(string? id)
{
return
this.HasID()
@@ -245,7 +247,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <inheritdoc />
public string GetRelativePathWithRoot()
{
- string rootFolderName = Path.GetFileName(this.RootPath) ?? "";
+ string rootFolderName = Path.GetFileName(this.RootPath);
return Path.Combine(rootFolderName, this.RelativeDirectoryPath);
}
@@ -254,7 +256,7 @@ namespace StardewModdingAPI.Framework.ModLoading
{
foreach (var reference in this.FakeContentPacks.ToArray())
{
- if (!reference.TryGetTarget(out ContentPack pack))
+ if (!reference.TryGetTarget(out ContentPack? pack))
{
this.FakeContentPacks.Remove(reference);
continue;
diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs
index c05005b8..afe38bfd 100644
--- a/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs
+++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -19,7 +17,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
/*********
** Public methods
*********/
- public static ConstructorInfo DeclaredConstructor(Type type, Type[] parameters = null)
+ public static ConstructorInfo DeclaredConstructor(Type type, Type[]? parameters = null)
{
// Harmony 1.x matched both static and instance constructors
return
@@ -27,7 +25,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
?? AccessTools.DeclaredConstructor(type, parameters, searchForStatic: true);
}
- public static ConstructorInfo Constructor(Type type, Type[] parameters = null)
+ public static ConstructorInfo Constructor(Type type, Type[]? parameters = null)
{
// Harmony 1.x matched both static and instance constructors
return
diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs
index fea8c100..9c8ba2b0 100644
--- a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs
+++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -30,7 +28,8 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
return new Harmony(id);
}
- public DynamicMethod Patch(MethodBase original, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null)
+ [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse", Justification = "If the user passes a null original method, we let it fail in the underlying Harmony instance instead of handling it here.")]
+ public DynamicMethod Patch(MethodBase original, HarmonyMethod? prefix = null, HarmonyMethod? postfix = null, HarmonyMethod? transpiler = null)
{
// In Harmony 1.x you could target a virtual method that's not implemented by the
// target type, but in Harmony 2.0 you need to target the concrete implementation.
@@ -60,7 +59,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
/// <param name="prefix">The prefix method, if any.</param>
/// <param name="postfix">The postfix method, if any.</param>
/// <param name="transpiler">The transpiler method, if any.</param>
- private string GetPatchTypesLabel(HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null)
+ private string GetPatchTypesLabel(HarmonyMethod? prefix = null, HarmonyMethod? postfix = null, HarmonyMethod? transpiler = null)
{
var patchTypes = new List<string>();
@@ -76,7 +75,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
/// <summary>Get a human-readable label for the method being patched.</summary>
/// <param name="method">The method being patched.</param>
- private string GetMethodLabel(MethodBase method)
+ private string GetMethodLabel(MethodBase? method)
{
return method != null
? $"method {method.DeclaringType?.FullName}.{method.Name}"
diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs
index 93124591..2b1ca54b 100644
--- a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs
+++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
@@ -23,7 +21,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
this.ImportMethodImpl(method);
}
- public HarmonyMethodFacade(Type type, string name, Type[] parameters = null)
+ public HarmonyMethodFacade(Type type, string name, Type[]? parameters = null)
{
this.ImportMethodImpl(AccessTools.Method(type, name, parameters));
}
@@ -40,7 +38,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
// internal code still handles null fine. For backwards compatibility, this bypasses
// the new restriction when the mod hasn't been updated for Harmony 2.0 yet.
- MethodInfo importMethod = typeof(HarmonyMethod).GetMethod("ImportMethod", BindingFlags.Instance | BindingFlags.NonPublic);
+ MethodInfo? importMethod = typeof(HarmonyMethod).GetMethod("ImportMethod", BindingFlags.Instance | BindingFlags.NonPublic);
if (importMethod == null)
throw new InvalidOperationException("Can't find 'HarmonyMethod.ImportMethod' method");
importMethod.Invoke(this, new object[] { methodInfo });
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs
index 92397c58..aea490c8 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using HarmonyLib;
using Mono.Cecil;
@@ -59,7 +57,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
if (this.ShouldRewrite)
{
// rewrite Harmony 1.x methods to Harmony 2.0
- MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ MethodReference? methodRef = RewriteHelper.AsMethodReference(instruction);
if (this.TryRewriteMethodsToFacade(module, methodRef))
{
this.OnChanged();
@@ -67,7 +65,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
}
// rewrite renamed fields
- FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
+ FieldReference? fieldRef = RewriteHelper.AsFieldReference(instruction);
if (fieldRef != null)
{
if (fieldRef.DeclaringType.FullName == "HarmonyLib.HarmonyMethod" && fieldRef.Name == "prioritiy")
@@ -95,13 +93,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <summary>Rewrite methods to use Harmony facades if needed.</summary>
/// <param name="module">The assembly module containing the method reference.</param>
/// <param name="methodRef">The method reference to map.</param>
- private bool TryRewriteMethodsToFacade(ModuleDefinition module, MethodReference methodRef)
+ private bool TryRewriteMethodsToFacade(ModuleDefinition module, MethodReference? methodRef)
{
if (!this.ReplacedTypes)
return false; // not Harmony (or already using Harmony 2.0)
// get facade type
- Type toType = methodRef?.DeclaringType.FullName switch
+ Type? toType = methodRef?.DeclaringType.FullName switch
{
"HarmonyLib.Harmony" => typeof(HarmonyInstanceFacade),
"HarmonyLib.AccessTools" => typeof(AccessToolsFacade),
@@ -112,9 +110,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
return false;
// map if there's a matching method
- if (RewriteHelper.HasMatchingSignature(toType, methodRef))
+ if (RewriteHelper.HasMatchingSignature(toType, methodRef!))
{
- methodRef.DeclaringType = module.ImportReference(toType);
+ methodRef!.DeclaringType = module.ImportReference(toType);
return true;
}
@@ -139,7 +137,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
{
string fullName = type.FullName.Replace("Harmony.", "HarmonyLib.");
string targetName = typeof(Harmony).AssemblyQualifiedName!.Replace(typeof(Harmony).FullName!, fullName);
- return Type.GetType(targetName, throwOnError: true);
+ return Type.GetType(targetName, throwOnError: true)!;
}
}
}
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs
index fc06e779..9c6a3980 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs
@@ -1,6 +1,5 @@
-#nullable disable
-
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -33,17 +32,17 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
{
// get field ref
- FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
+ FieldReference? fieldRef = RewriteHelper.AsFieldReference(instruction);
if (fieldRef == null || !this.ShouldValidate(fieldRef.DeclaringType))
return false;
// skip if not broken
- FieldDefinition fieldDefinition = fieldRef.Resolve();
+ FieldDefinition? fieldDefinition = fieldRef.Resolve();
if (fieldDefinition?.HasConstant == false)
return false;
// rewrite if possible
- TypeDefinition declaringType = fieldRef.DeclaringType.Resolve();
+ TypeDefinition? declaringType = fieldRef.DeclaringType.Resolve();
bool isRead = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld;
return
this.TryRewriteToProperty(module, instruction, fieldRef, declaringType, isRead)
@@ -56,7 +55,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
*********/
/// <summary>Whether references to the given type should be validated.</summary>
/// <param name="type">The type reference.</param>
- private bool ShouldValidate(TypeReference type)
+ private bool ShouldValidate([NotNullWhen(true)] TypeReference? type)
{
return type != null && this.RewriteReferencesToAssemblies.Contains(type.Scope.Name);
}
@@ -70,8 +69,8 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
private bool TryRewriteToProperty(ModuleDefinition module, Instruction instruction, FieldReference fieldRef, TypeDefinition declaringType, bool isRead)
{
// get equivalent property
- PropertyDefinition property = declaringType?.Properties.FirstOrDefault(p => p.Name == fieldRef.Name);
- MethodDefinition method = isRead ? property?.GetMethod : property?.SetMethod;
+ PropertyDefinition? property = declaringType?.Properties.FirstOrDefault(p => p.Name == fieldRef.Name);
+ MethodDefinition? method = isRead ? property?.GetMethod : property?.SetMethod;
if (method == null)
return false;
@@ -86,14 +85,14 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <summary>Try rewriting the field into a matching const field.</summary>
/// <param name="instruction">The CIL instruction to rewrite.</param>
/// <param name="field">The field definition.</param>
- private bool TryRewriteToConstField(Instruction instruction, FieldDefinition field)
+ private bool TryRewriteToConstField(Instruction instruction, FieldDefinition? field)
{
// must have been a static field read, and the new field must be const
if (instruction.OpCode != OpCodes.Ldsfld || field?.HasConstant != true)
return false;
// get opcode for value type
- Instruction loadInstruction = RewriteHelper.GetLoadValueInstruction(field.Constant);
+ Instruction? loadInstruction = RewriteHelper.GetLoadValueInstruction(field.Constant);
if (loadInstruction == null)
return false;
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs
index 4860072c..601ecbbc 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs
@@ -1,6 +1,5 @@
-#nullable disable
-
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -33,7 +32,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
{
// get method ref
- MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ MethodReference? methodRef = RewriteHelper.AsMethodReference(instruction);
if (methodRef == null || !this.ShouldValidate(methodRef.DeclaringType))
return false;
@@ -42,13 +41,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
return false;
// get type
- var type = methodRef.DeclaringType.Resolve();
+ TypeDefinition? type = methodRef.DeclaringType.Resolve();
if (type == null)
return false;
// get method definition
- MethodDefinition method = null;
- foreach (var match in type.Methods.Where(p => p.Name == methodRef.Name))
+ MethodDefinition? method = null;
+ foreach (MethodDefinition match in type.Methods.Where(p => p.Name == methodRef.Name))
{
// reference matches initial parameters of definition
if (methodRef.Parameters.Count >= match.Parameters.Count || !this.InitialParametersMatch(methodRef, match))
@@ -72,7 +71,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
return false; // SMAPI needs to load the value onto the stack before the method call, but the optional parameter type wasn't recognized
// rewrite method reference
- foreach (Instruction loadInstruction in loadInstructions)
+ foreach (Instruction? loadInstruction in loadInstructions)
cil.InsertBefore(instruction, loadInstruction);
instruction.Operand = module.ImportReference(method);
@@ -86,7 +85,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
*********/
/// <summary>Whether references to the given type should be validated.</summary>
/// <param name="type">The type reference.</param>
- private bool ShouldValidate(TypeReference type)
+ private bool ShouldValidate([NotNullWhen(true)] TypeReference? type)
{
return type != null && this.RewriteReferencesToAssemblies.Contains(type.Scope.Name);
}
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs
index 00daf337..2e2f6316 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs
@@ -1,6 +1,5 @@
-#nullable disable
-
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -28,7 +27,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <param name="fromType">The type whose methods to remap.</param>
/// <param name="toType">The type with methods to map to.</param>
/// <param name="nounPhrase">A brief noun phrase indicating what the instruction finder matches (or <c>null</c> to generate one).</param>
- public MethodParentRewriter(string fromType, Type toType, string nounPhrase = null)
+ public MethodParentRewriter(string fromType, Type toType, string? nounPhrase = null)
: base(nounPhrase ?? $"{fromType.Split('.').Last()} methods")
{
this.FromType = fromType;
@@ -39,14 +38,14 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <param name="fromType">The type whose methods to remap.</param>
/// <param name="toType">The type with methods to map to.</param>
/// <param name="nounPhrase">A brief noun phrase indicating what the instruction finder matches (or <c>null</c> to generate one).</param>
- public MethodParentRewriter(Type fromType, Type toType, string nounPhrase = null)
- : this(fromType.FullName, toType, nounPhrase) { }
+ public MethodParentRewriter(Type fromType, Type toType, string? nounPhrase = null)
+ : this(fromType.FullName!, toType, nounPhrase) { }
/// <inheritdoc />
public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
{
// get method ref
- MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ MethodReference? methodRef = RewriteHelper.AsMethodReference(instruction);
if (!this.IsMatch(methodRef))
return false;
@@ -61,7 +60,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
*********/
/// <summary>Get whether a CIL instruction matches.</summary>
/// <param name="methodRef">The method reference.</param>
- private bool IsMatch(MethodReference methodRef)
+ private bool IsMatch([NotNullWhen(true)] MethodReference? methodRef)
{
return
methodRef != null
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs
index bdc4c4f3..a81cb5be 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using Mono.Cecil;
using StardewModdingAPI.Framework.ModLoading.Framework;
@@ -19,7 +17,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
private readonly Type ToType;
/// <summary>Get whether a matched type should be ignored.</summary>
- private readonly Func<TypeReference, bool> ShouldIgnore;
+ private readonly Func<TypeReference, bool>? ShouldIgnore;
/*********
@@ -29,7 +27,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <param name="fromTypeFullName">The full type name to which to find references.</param>
/// <param name="toType">The new type to reference.</param>
/// <param name="shouldIgnore">Get whether a matched type should be ignored.</param>
- public TypeReferenceRewriter(string fromTypeFullName, Type toType, Func<TypeReference, bool> shouldIgnore = null)
+ public TypeReferenceRewriter(string fromTypeFullName, Type toType, Func<TypeReference, bool>? shouldIgnore = null)
: base($"{fromTypeFullName} type")
{
this.FromTypeName = fromTypeFullName;
diff --git a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs
index 4af7c1e7..0d3aff9f 100644
--- a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs
+++ b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.IO;
@@ -38,7 +36,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Symbols
/// <param name="fileName">The assembly file name.</param>
public ISymbolReader GetSymbolReader(ModuleDefinition module, string fileName)
{
- return this.SymbolsByAssemblyPath.TryGetValue(module.Name, out Stream symbolData)
+ return this.SymbolsByAssemblyPath.TryGetValue(module.Name, out Stream? symbolData)
? new SymbolReader(module, symbolData)
: this.BaseProvider.GetSymbolReader(module, fileName);
}
@@ -48,7 +46,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Symbols
/// <param name="symbolStream">The loaded symbol file stream.</param>
public ISymbolReader GetSymbolReader(ModuleDefinition module, Stream symbolStream)
{
- return this.SymbolsByAssemblyPath.TryGetValue(module.Name, out Stream symbolData)
+ return this.SymbolsByAssemblyPath.TryGetValue(module.Name, out Stream? symbolData)
? new SymbolReader(module, symbolData)
: this.BaseProvider.GetSymbolReader(module, symbolStream);
}
diff --git a/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs b/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs
index 248c29fc..d81d763e 100644
--- a/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs
+++ b/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -18,7 +16,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <c>TKey</c> in the above example). If all components are equal after substitution, and the
/// tokens can all be mapped to the same generic type, the types are considered equal.
/// </remarks>
- internal class TypeReferenceComparer : IEqualityComparer<TypeReference>
+ internal class TypeReferenceComparer : IEqualityComparer<TypeReference?>
{
/*********
** Public methods
@@ -26,7 +24,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <summary>Get whether the specified objects are equal.</summary>
/// <param name="a">The first object to compare.</param>
/// <param name="b">The second object to compare.</param>
- public bool Equals(TypeReference a, TypeReference b)
+ public bool Equals(TypeReference? a, TypeReference? b)
{
if (a == null || b == null)
return a == b;
@@ -54,7 +52,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <param name="typeB">The second type to compare.</param>
private bool HeuristicallyEquals(TypeReference typeA, TypeReference typeB)
{
- bool HeuristicallyEquals(string typeNameA, string typeNameB, IDictionary<string, string> tokenMap)
+ bool HeuristicallyEqualsImpl(string typeNameA, string typeNameB, IDictionary<string, string> tokenMap)
{
// analyze type names
bool hasTokensA = typeNameA.Contains("!");
@@ -82,14 +80,14 @@ namespace StardewModdingAPI.Framework.ModLoading
for (int i = 0; i < symbolsA.Length; i++)
{
- if (!HeuristicallyEquals(symbolsA[i], symbolsB[i], tokenMap))
+ if (!HeuristicallyEqualsImpl(symbolsA[i], symbolsB[i], tokenMap))
return false;
}
return true;
}
- return HeuristicallyEquals(typeA.FullName, typeB.FullName, new Dictionary<string, string>());
+ return HeuristicallyEqualsImpl(typeA.FullName, typeB.FullName, new Dictionary<string, string>());
}
/// <summary>Map a generic type placeholder (like <c>!0</c>) to its actual type.</summary>
@@ -99,7 +97,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <returns>Returns the previously-mapped type if applicable, else the <paramref name="type"/>.</returns>
private string MapPlaceholder(string placeholder, string type, IDictionary<string, string> map)
{
- if (map.TryGetValue(placeholder, out string result))
+ if (map.TryGetValue(placeholder, out string? result))
return result;
map[placeholder] = type;