diff --git a/BSIPA.sln b/BSIPA.sln
index 93a8e3aa..3e5a2bda 100644
--- a/BSIPA.sln
+++ b/BSIPA.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28729.10
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.31911.260
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IPA", "IPA\IPA.csproj", "{14092533-98BB-40A4-9AFC-27BB75672A70}"
ProjectSection(ProjectDependencies) = postProject
@@ -24,7 +24,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.github\workflows\docs.yml = .github\workflows\docs.yml
README.md = README.md
.github\release_draft.yml = .github\release_draft.yml
- System.Diagnostics.CodeAnalysis.cs = System.Diagnostics.CodeAnalysis.cs
.github\workflows\tag_docs.yml = .github\workflows\tag_docs.yml
EndProjectSection
EndProject
diff --git a/Common.props b/Common.props
index d76b2ec5..f33175a4 100644
--- a/Common.props
+++ b/Common.props
@@ -14,6 +14,14 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
\ No newline at end of file
diff --git a/Common.targets b/Common.targets
index 56750be5..f6c26ae1 100644
--- a/Common.targets
+++ b/Common.targets
@@ -1,8 +1,4 @@
-
-
-
-
\ No newline at end of file
diff --git a/IPA.Loader/Config/Data/List.cs b/IPA.Loader/Config/Data/List.cs
index d4f48397..764c619b 100644
--- a/IPA.Loader/Config/Data/List.cs
+++ b/IPA.Loader/Config/Data/List.cs
@@ -1,4 +1,5 @@
-using IPA.Utilities;
+#nullable enable
+using IPA.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -10,9 +11,9 @@ namespace IPA.Config.Data
/// A list of s for serialization by an .
/// Use or to create.
///
- public sealed class List : Value, IList
+ public sealed class List : Value, IList
{
- private readonly List values = new List();
+ private readonly List values = new();
internal List() { }
@@ -22,7 +23,7 @@ namespace IPA.Config.Data
/// the index to retrieve the at
/// the at
///
- public Value this[int index] { get => values[index]; set => values[index] = value; }
+ public Value? this[int index] { get => values[index]; set => values[index] = value; }
///
/// Gets the number of elements in the .
@@ -30,21 +31,22 @@ namespace IPA.Config.Data
///
public int Count => values.Count;
- bool ICollection.IsReadOnly => ((IList)values).IsReadOnly;
+ bool ICollection.IsReadOnly => ((IList)values).IsReadOnly;
///
/// Adds a to the end of this .
///
/// the to add
///
- public void Add(Value item) => values.Add(item);
+ public void Add(Value? item) => values.Add(item);
///
/// Adds a range of s to the end of this .
///
/// the range of s to add
- public void AddRange(IEnumerable vals)
+ public void AddRange(IEnumerable vals)
{
+ if (vals is null) throw new ArgumentNullException(nameof(vals));
foreach (var val in vals) Add(val);
}
@@ -60,7 +62,7 @@ namespace IPA.Config.Data
/// the to check for
/// if the item was founc, otherwise
///
- public bool Contains(Value item) => values.Contains(item);
+ public bool Contains(Value? item) => values.Contains(item);
///
/// Copies the s in the to the in .
@@ -68,14 +70,14 @@ namespace IPA.Config.Data
/// the to copy to
/// the starting index to copy to
///
- public void CopyTo(Value[] array, int arrayIndex) => values.CopyTo(array, arrayIndex);
+ public void CopyTo(Value?[] array, int arrayIndex) => values.CopyTo(array, arrayIndex);
///
/// Gets an enumerator to enumerate the .
///
/// an for this
///
- public IEnumerator GetEnumerator() => ((IList)values).GetEnumerator();
+ public IEnumerator GetEnumerator() => ((IList)values).GetEnumerator();
///
/// Gets the index that a given is in the .
@@ -83,7 +85,7 @@ namespace IPA.Config.Data
/// the to search for
/// the index that the was at, or -1.
///
- public int IndexOf(Value item) => values.IndexOf(item);
+ public int IndexOf(Value? item) => values.IndexOf(item);
///
/// Inserts a at an index.
@@ -91,7 +93,7 @@ namespace IPA.Config.Data
/// the index to insert at
/// the to insert
///
- public void Insert(int index, Value item) => values.Insert(index, item);
+ public void Insert(int index, Value? item) => values.Insert(index, item);
///
/// Removes a from the .
@@ -99,7 +101,7 @@ namespace IPA.Config.Data
/// the to remove
/// if the item was removed, otherwise
///
- public bool Remove(Value item) => values.Remove(item);
+ public bool Remove(Value? item) => values.Remove(item);
///
/// Removes a at an index.
@@ -115,7 +117,7 @@ namespace IPA.Config.Data
public override string ToString()
=> $"[{string.Join(",",this.Select(v => v?.ToString() ?? "null").StrJP())}]";
- IEnumerator IEnumerable.GetEnumerator() => ((IList)values).GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
diff --git a/IPA.Loader/Config/Data/Map.cs b/IPA.Loader/Config/Data/Map.cs
index 21be20b4..8ed8f17c 100644
--- a/IPA.Loader/Config/Data/Map.cs
+++ b/IPA.Loader/Config/Data/Map.cs
@@ -1,4 +1,5 @@
-using IPA.Utilities;
+#nullable enable
+using IPA.Utilities;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
@@ -10,10 +11,10 @@ namespace IPA.Config.Data
/// A ordered map of to for serialization by an .
/// Use or to create.
///
- public sealed class Map : Value, IDictionary
+ public sealed class Map : Value, IDictionary
{
- private readonly Dictionary values = new Dictionary();
- private readonly List keyOrder = new List();
+ private readonly Dictionary values = new();
+ private readonly List keyOrder = new();
internal Map() { }
@@ -23,7 +24,7 @@ namespace IPA.Config.Data
/// the key to get the value associated with
/// the value associated with the
///
- public Value this[string key] { get => values[key]; set => values[key] = value; }
+ public Value? this[string key] { get => values[key]; set => values[key] = value; }
///
/// Gets a collection of the keys for the .
@@ -39,7 +40,7 @@ namespace IPA.Config.Data
/// guarantee that order is maintained.
///
///
- public ICollection Values => values.Values;
+ public ICollection Values => values.Values;
///
/// Gets the number of key-value pairs in this .
@@ -47,7 +48,7 @@ namespace IPA.Config.Data
///
public int Count => values.Count;
- bool ICollection>.IsReadOnly => ((IDictionary)values).IsReadOnly;
+ bool ICollection>.IsReadOnly => ((IDictionary)values).IsReadOnly;
///
/// Adds a new with a given key.
@@ -55,13 +56,13 @@ namespace IPA.Config.Data
/// the key to put the value at
/// the to add
///
- public void Add(string key, Value value)
+ public void Add(string key, Value? value)
{
values.Add(key, value);
keyOrder.Add(key);
}
- void ICollection>.Add(KeyValuePair item)
+ void ICollection>.Add(KeyValuePair item)
=> Add(item.Key, item.Value);
///
@@ -74,8 +75,8 @@ namespace IPA.Config.Data
keyOrder.Clear();
}
- bool ICollection>.Contains(KeyValuePair item)
- => ((IDictionary)values).Contains(item);
+ bool ICollection>.Contains(KeyValuePair item)
+ => ((IDictionary)values).Contains(item);
///
/// Checks if the contains a given .
@@ -85,18 +86,18 @@ namespace IPA.Config.Data
///
public bool ContainsKey(string key) => values.ContainsKey(key);
- void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex)
- => ((IDictionary)values).CopyTo(array, arrayIndex);
+ void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex)
+ => ((IDictionary)values).CopyTo(array, arrayIndex);
///
/// Enumerates the 's key-value pairs.
///
/// an of key-value pairs in this
///
- public IEnumerator> GetEnumerator()
+ public IEnumerator> GetEnumerator()
{
foreach (var key in keyOrder)
- yield return new KeyValuePair(key, this[key]);
+ yield return new KeyValuePair(key, this[key]);
}
///
@@ -107,8 +108,8 @@ namespace IPA.Config.Data
///
public bool Remove(string key) => values.Remove(key) && keyOrder.Remove(key);
- bool ICollection>.Remove(KeyValuePair item)
- => ((IDictionary)values).Remove(item) && (keyOrder.Remove(item.Key) || true);
+ bool ICollection>.Remove(KeyValuePair item)
+ => ((IDictionary)values).Remove(item) && (keyOrder.Remove(item.Key) || true);
///
/// Gets the value associated with the specified key.
@@ -117,7 +118,7 @@ namespace IPA.Config.Data
/// the target location of the retrieved object
/// if the key was found and set, otherwise
///
- public bool TryGetValue(string key, out Value value) => values.TryGetValue(key, out value);
+ public bool TryGetValue(string key, out Value? value) => values.TryGetValue(key, out value);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
diff --git a/IPA.Loader/Config/Data/Primitives.cs b/IPA.Loader/Config/Data/Primitives.cs
index c03b3c90..5abc6d88 100644
--- a/IPA.Loader/Config/Data/Primitives.cs
+++ b/IPA.Loader/Config/Data/Primitives.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable enable
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -12,10 +13,28 @@ namespace IPA.Config.Data
///
public sealed class Text : Value
{
+ ///
+ /// Constructs an empty object.
+ ///
+ [Obsolete("Use the String constructor.")]
+ public Text()
+ {
+ Value = null!;
+ }
+
+ ///
+ /// Constructs a object containing the provided value.
+ ///
+ /// The value to construct with.
+ public Text(string value)
+ {
+ Value = value;
+ }
+
///
/// The actual value of this object.
///
- public string Value { get; set; }
+ public string Value { get; init; }
///
/// Converts this into a human-readable format.
@@ -30,6 +49,24 @@ namespace IPA.Config.Data
///
public sealed class Integer : Value
{
+ ///
+ /// Constructs an empty object.
+ ///
+ [Obsolete("Use the long constructor.")]
+ public Integer()
+ {
+ Value = 0;
+ }
+
+ ///
+ /// Constructs a object containing the provided value.
+ ///
+ /// The value to construct with.
+ public Integer(long value)
+ {
+ Value = value;
+ }
+
///
/// The actual value of the object.
///
@@ -50,10 +87,28 @@ namespace IPA.Config.Data
///
/// A representing a floating point value. This may hold a
- /// 's worth of data.
+ /// 's worth of data.
///
public sealed class FloatingPoint : Value
{
+ ///
+ /// Constructs an empty object.
+ ///
+ [Obsolete("Use the long constructor.")]
+ public FloatingPoint()
+ {
+ Value = 0;
+ }
+
+ ///
+ /// Constructs a object containing the provided value.
+ ///
+ /// The value to construct with.
+ public FloatingPoint(decimal value)
+ {
+ Value = value;
+ }
+
///
/// The actual value fo this object.
///
@@ -76,16 +131,37 @@ namespace IPA.Config.Data
/// A representing a boolean value.
///
public sealed class Boolean : Value
- {
+ {
+ ///
+ /// Constructs an empty object.
+ ///
+ [Obsolete("Use the long constructor.")]
+ public Boolean()
+ {
+ Value = false;
+ }
+
+ ///
+ /// Constructs a object containing the provided value.
+ ///
+ /// The value to construct with.
+ public Boolean(bool value)
+ {
+ Value = value;
+ }
+
///
/// The actual value fo this object.
///
- public bool Value { get; set; }
-
+ public bool Value { get; set; }
+
+
///
/// Converts this into a human-readable format.
///
/// the result of Value.ToString().ToLower()
- public override string ToString() => Value.ToString().ToLower();
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase",
+ Justification = "ToLower is the desired display value.")]
+ public override string ToString() => Value.ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture);
}
}
diff --git a/IPA.Loader/Config/Data/Value.cs b/IPA.Loader/Config/Data/Value.cs
index 2e0e4eb7..0d61cebd 100644
--- a/IPA.Loader/Config/Data/Value.cs
+++ b/IPA.Loader/Config/Data/Value.cs
@@ -1,6 +1,8 @@
-using System;
+#nullable enable
+using System;
using System.Collections;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -25,21 +27,21 @@ namespace IPA.Config.Data
/// Creates a Null .
///
///
- public static Value Null() => null;
+ public static Value? Null() => null;
///
/// Creates an empty .
///
/// an empty
///
- public static List List() => new List();
+ public static List List() => new();
///
/// Creates an empty .
///
/// an empty
///
///
- public static Map Map() => new Map();
+ public static Map Map() => new();
///
/// Creates a new representing a .
@@ -47,14 +49,16 @@ namespace IPA.Config.Data
/// the value to wrap
/// a wrapping
///
- public static Text From(string val) => Text(val);
+ [return: NotNullIfNotNull("val")]
+ public static Text? From(string? val) => Text(val);
///
/// Creates a new object wrapping a .
///
/// the value to wrap
/// a wrapping
///
- public static Text Text(string val) => val == null ? null : new Text { Value = val };
+ [return: NotNullIfNotNull("val")]
+ public static Text? Text(string? val) => val == null ? null : new(val);
///
/// Creates a new wrapping a .
@@ -69,7 +73,7 @@ namespace IPA.Config.Data
/// the value to wrap
/// a wrapping
///
- public static Integer Integer(long val) => new Integer { Value = val };
+ public static Integer Integer(long val) => new(val);
///
/// Creates a new wrapping a .
@@ -84,7 +88,7 @@ namespace IPA.Config.Data
/// the value to wrap
/// a wrapping
///
- public static FloatingPoint Float(decimal val) => new FloatingPoint { Value = val };
+ public static FloatingPoint Float(decimal val) => new(val);
///
/// Creates a new wrapping a .
@@ -99,7 +103,7 @@ namespace IPA.Config.Data
/// the value to wrap
/// a wrapping
///
- public static Boolean Bool(bool val) => new Boolean { Value = val };
+ public static Boolean Bool(bool val) => new(val);
///
/// Creates a new holding the content of an
@@ -108,9 +112,10 @@ namespace IPA.Config.Data
/// the s to initialize the with
/// a containing the content of
///
- public static List From(IEnumerable vals)
+ [return: NotNullIfNotNull("vals")]
+ public static List? From(IEnumerable? vals)
{
- if (vals == null) return null;
+ if (vals is null) return null;
var l = List();
l.AddRange(vals);
return l;
@@ -124,7 +129,7 @@ namespace IPA.Config.Data
/// a containing the content of
///
///
- public static Map From(IDictionary vals) => From(vals as IEnumerable>);
+ public static Map From(IDictionary vals) => From(vals as IEnumerable>);
///
/// Creates a new holding the content of an
@@ -134,9 +139,10 @@ namespace IPA.Config.Data
/// a containing the content of
///
///
- public static Map From(IEnumerable> vals)
+ [return: NotNullIfNotNull("vals")]
+ public static Map? From(IEnumerable>? vals)
{
- if (vals == null) return null;
+ if (vals is null) return null;
var m = Map();
foreach (var v in vals) m.Add(v.Key, v.Value);
return m;
diff --git a/IPA.Loader/Config/SelfConfig.cs b/IPA.Loader/Config/SelfConfig.cs
index 1bc877b8..bc0d2b04 100644
--- a/IPA.Loader/Config/SelfConfig.cs
+++ b/IPA.Loader/Config/SelfConfig.cs
@@ -175,7 +175,7 @@ namespace IPA.Config
&& CommandLineValues.YeetMods;
// LINE: ignore
- [NonNullable, UseConverter(typeof(CollectionConverter>))]
+ [NonNullable, UseConverter(typeof(CollectionConverter>))]
public virtual HashSet GameAssemblies { get; set; } = new HashSet
{
// LINE: ignore 5
diff --git a/IPA.Loader/Config/Stores/Attributes.cs b/IPA.Loader/Config/Stores/Attributes.cs
index 574dfd80..66c63e16 100644
--- a/IPA.Loader/Config/Stores/Attributes.cs
+++ b/IPA.Loader/Config/Stores/Attributes.cs
@@ -1,6 +1,8 @@
-using IPA.Config.Stores.Converters;
+#nullable enable
+using IPA.Config.Stores.Converters;
using System;
using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace IPA.Config.Stores.Attributes
@@ -37,23 +39,25 @@ namespace IPA.Config.Stores.Attributes
///
/// Gets whether or not to use the default converter for the member type instead of the specified type.
///
+ [MemberNotNullWhen(false, nameof(ConverterType))]
public bool UseDefaultConverterForType { get; }
///
/// Gets the type of the converter to use.
///
- public Type ConverterType { get; }
+ public Type? ConverterType { get; }
///
/// Gets the target type of the converter if it is avaliable at instantiation time, otherwise
/// .
///
- public Type ConverterTargetType { get; }
+ public Type? ConverterTargetType { get; }
///
/// Gets whether or not this converter is a generic .
///
- public bool IsGenericConverter => ConverterTargetType != null;
+ [MemberNotNullWhen(true, nameof(ConverterTargetType))]
+ public bool IsGenericConverter => ConverterTargetType is not null;
///
/// Creates a new specifying to use the default converter type for the target member.
@@ -67,11 +71,17 @@ namespace IPA.Config.Stores.Attributes
/// the type to assign to
public UseConverterAttribute(Type converterType)
{
+ if (converterType is null)
+ throw new ArgumentNullException(nameof(converterType));
+
UseDefaultConverterForType = false;
ConverterType = converterType;
+ if (converterType.IsValueType)
+ throw new ArgumentException("Type is not a value converter!");
+
var baseT = ConverterType.BaseType;
- while (baseT != null && baseT != typeof(object) &&
+ while (baseT != typeof(object) &&
(!baseT.IsGenericType || baseT.GetGenericTypeDefinition() != typeof(ValueConverter<>)))
baseT = baseT.BaseType;
if (baseT == typeof(object)) ConverterTargetType = null;
diff --git a/IPA.Loader/Config/Stores/CollectionConverter.cs b/IPA.Loader/Config/Stores/CollectionConverter.cs
index 635ba49c..16093540 100644
--- a/IPA.Loader/Config/Stores/CollectionConverter.cs
+++ b/IPA.Loader/Config/Stores/CollectionConverter.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable enable
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -14,7 +15,7 @@ namespace IPA.Config.Stores.Converters
/// the type of the items in the collection
/// the instantiated type of collection
public class CollectionConverter : ValueConverter
- where TCollection : ICollection
+ where TCollection : ICollection
{
///
/// Creates a using the default converter for the
@@ -54,7 +55,7 @@ namespace IPA.Config.Stores.Converters
///
protected void PopulateFromValue(TCollection col, List list, object parent)
{
- //Logger.log.Debug($"CollectionConverter<{typeof(T)}, {typeof(TCollection)}>({BaseConverter.GetType()}).PopulateFromValue([object], {list}, {parent.GetType()})");
+ if (list is null) throw new ArgumentNullException(nameof(list));
foreach (var it in list)
col.Add(BaseConverter.FromValue(it, parent));
}
@@ -66,9 +67,9 @@ namespace IPA.Config.Stores.Converters
/// the object that will own the resulting
/// a new holding the deserialized content of
///
- public override TCollection FromValue(Value value, object parent)
+ public override TCollection FromValue(Value? value, object parent)
{
- if (!(value is List list)) throw new ArgumentException("Argument not a List", nameof(value));
+ if (value is not List list) throw new ArgumentException("Argument not a List", nameof(value));
var col = Create(list.Count, parent);
PopulateFromValue(col, list, parent);
@@ -81,7 +82,7 @@ namespace IPA.Config.Stores.Converters
/// the object owning
/// the that was serialized into
///
- public override Value ToValue(TCollection obj, object parent)
+ public override Value? ToValue(TCollection? obj, object parent)
=> Value.From(obj.Select(t => BaseConverter.ToValue(t, parent)));
}
///
@@ -92,7 +93,7 @@ namespace IPA.Config.Stores.Converters
/// the type of the converter to use for
///
public sealed class CollectionConverter : CollectionConverter
- where TCollection : ICollection
+ where TCollection : ICollection
where TConverter : ValueConverter, new()
{
///
@@ -110,7 +111,7 @@ namespace IPA.Config.Stores.Converters
///
/// the element type of the
///
- public class ISetConverter : CollectionConverter>
+ public class ISetConverter : CollectionConverter>
{
///
/// Creates an using the default converter for .
@@ -128,8 +129,8 @@ namespace IPA.Config.Stores.Converters
/// the size to initialize it to
/// the object that will own the new object
/// the new
- protected override ISet Create(int size, object parent)
- => new HashSet();
+ protected override ISet Create(int size, object parent)
+ => new HashSet();
}
///
/// An which default constructs a converter for use as the value converter.
@@ -155,7 +156,7 @@ namespace IPA.Config.Stores.Converters
///
/// the element type of the
///
- public class ListConverter : CollectionConverter>
+ public class ListConverter : CollectionConverter>
{
///
/// Creates an using the default converter for .
@@ -173,8 +174,8 @@ namespace IPA.Config.Stores.Converters
/// the size to initialize it to
/// the object that will own the new object
/// the new
- protected override List Create(int size, object parent)
- => new List(size);
+ protected override List Create(int size, object parent)
+ => new(size);
}
///
/// A which default constructs a converter for use as the value converter.
@@ -199,7 +200,7 @@ namespace IPA.Config.Stores.Converters
///
/// the element type of the
///
- public class IListConverter : CollectionConverter>
+ public class IListConverter : CollectionConverter>
{
///
/// Creates an using the default converter for .
@@ -217,8 +218,8 @@ namespace IPA.Config.Stores.Converters
/// the size to initialize it to
/// the object that will own the new object
/// the new
- protected override IList Create(int size, object parent)
- => new List(size);
+ protected override IList Create(int size, object parent)
+ => new List(size);
}
///
/// An which default constructs a converter for use as the value converter.
diff --git a/IPA.Loader/Config/Stores/Converters.cs b/IPA.Loader/Config/Stores/Converters.cs
index 7821b90a..12e222f1 100644
--- a/IPA.Loader/Config/Stores/Converters.cs
+++ b/IPA.Loader/Config/Stores/Converters.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Data;
+#nullable enable
+using IPA.Config.Data;
using IPA.Config.Stores.Attributes;
using IPA.Logging;
using System;
@@ -22,7 +23,7 @@ namespace IPA.Config.Stores.Converters
///
/// the to get the integral value of
/// the integral value of , or
- public static long? IntValue(Value val)
+ public static long? IntValue(Value? val)
=> val is Integer inte ? inte.Value :
val is FloatingPoint fp ? fp.AsInteger()?.Value :
null;
@@ -32,7 +33,7 @@ namespace IPA.Config.Stores.Converters
///
/// the to get the floaing point value of
/// the floaing point value of , or
- public static decimal? FloatValue(Value val)
+ public static decimal? FloatValue(Value? val)
=> val is FloatingPoint fp ? fp.Value :
val is Integer inte ? inte.AsFloat()?.Value :
null;
@@ -83,7 +84,7 @@ namespace IPA.Config.Stores.Converters
}
//Logger.log.Debug($"gives converter for value type {t}");
- var valConv = Activator.CreateInstance(typeof(ValConv<>).MakeGenericType(t)) as IValConv;
+ var valConv = (IValConv)Activator.CreateInstance(typeof(ValConv<>).MakeGenericType(t));
return valConv.Get();
}
@@ -117,7 +118,7 @@ namespace IPA.Config.Stores.Converters
IValConv, IValConv,
IValConv
{
- internal static readonly ValConvImpls Impl = new ValConvImpls();
+ internal static readonly ValConvImpls Impl = new();
Type IValConv.Get() => typeof(CharConverter);
Type IValConv.Get() => typeof(LongConverter);
Type IValConv.Get() => typeof(ULongConverter);
@@ -145,7 +146,7 @@ namespace IPA.Config.Stores.Converters
/// the type of the that this works on
public static class Converter
{
- private static ValueConverter defaultConverter = null;
+ private static ValueConverter? defaultConverter;
///
/// Gets the default for the current type.
///
@@ -158,7 +159,7 @@ namespace IPA.Config.Stores.Converters
//Logger.log.Debug($"Converter<{t}>.MakeDefault()");
static ValueConverter MakeInstOf(Type ty)
- => Activator.CreateInstance(ty) as ValueConverter;
+ => (ValueConverter)Activator.CreateInstance(ty);
return MakeInstOf(Converter.GetDefaultConverterType(t));
}
@@ -193,16 +194,16 @@ namespace IPA.Config.Stores.Converters
/// the tree to convert
/// the object which will own the created object
/// the object represented by
- public override T? FromValue(Value value, object parent)
- => value == null ? null : new T?(baseConverter.FromValue(value, parent));
+ public override T? FromValue(Value? value, object parent)
+ => value is null ? null : new T?(baseConverter.FromValue(value, parent));
///
/// Converts a nullable to a tree.
///
/// the value to serialize
/// the object which owns
/// a tree representing .
- public override Value ToValue(T? obj, object parent)
- => obj == null ? null : baseConverter.ToValue(obj.Value, parent);
+ public override Value? ToValue(T? obj, object parent)
+ => obj is null ? null : baseConverter.ToValue(obj.Value, parent);
}
///
@@ -237,7 +238,7 @@ namespace IPA.Config.Stores.Converters
/// the object which will own the created object
/// the deserialized enum value
/// if is not a node
- public override T FromValue(Value value, object parent)
+ public override T FromValue(Value? value, object parent)
=> value is Text t
? (T)Enum.Parse(typeof(T), t.Value)
: throw new ArgumentException("Value not a string", nameof(value));
@@ -248,8 +249,8 @@ namespace IPA.Config.Stores.Converters
/// the value to serialize
/// the object which owns
/// a node representing
- public override Value ToValue(T obj, object parent)
- => Value.Text(obj.ToString());
+ public override Value? ToValue(T? obj, object parent)
+ => Value.Text(obj?.ToString());
}
///
@@ -267,7 +268,7 @@ namespace IPA.Config.Stores.Converters
/// the object which will own the created object
/// the deserialized enum value
/// if is not a node
- public override T FromValue(Value value, object parent)
+ public override T FromValue(Value? value, object parent)
=> value is Text t
? (T)Enum.Parse(typeof(T), t.Value, true)
: throw new ArgumentException("Value not a string", nameof(value));
@@ -278,8 +279,8 @@ namespace IPA.Config.Stores.Converters
/// the value to serialize
/// the object which owns
/// a node representing
- public override Value ToValue(T obj, object parent)
- => Value.Text(obj.ToString());
+ public override Value? ToValue(T? obj, object parent)
+ => Value.Text(obj?.ToString());
}
///
@@ -296,7 +297,7 @@ namespace IPA.Config.Stores.Converters
/// the object which will own the created object
/// the deserialized enum value
/// if is not a numeric node
- public override T FromValue(Value value, object parent)
+ public override T FromValue(Value? value, object parent)
=> (T)Enum.ToObject(typeof(T), Converter.IntValue(value)
?? throw new ArgumentException("Value not a numeric node", nameof(value)));
@@ -306,7 +307,7 @@ namespace IPA.Config.Stores.Converters
/// the value to serialize
/// the object which owns
/// an node representing
- public override Value ToValue(T obj, object parent)
+ public override Value ToValue(T? obj, object parent)
=> Value.Integer(Convert.ToInt64(obj));
}
@@ -314,7 +315,7 @@ namespace IPA.Config.Stores.Converters
/// A converter for instances of .
///
/// the value type of the dictionary
- public class IDictionaryConverter : ValueConverter>
+ public class IDictionaryConverter : ValueConverter>
{
///
/// Gets the converter for the dictionary's value type.
@@ -338,9 +339,9 @@ namespace IPA.Config.Stores.Converters
/// the to convert
/// the parent that will own the resulting object
/// the deserialized dictionary
- public override IDictionary FromValue(Value value, object parent)
- => (value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
- ?.ToDictionary(p => p.Key, p => p.val)
+ public override IDictionary FromValue(Value? value, object parent)
+ => ((value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
+ ?.ToDictionary(p => p.Key, p => p.val))
?? throw new ArgumentException("Value not a map", nameof(value));
///
@@ -349,8 +350,8 @@ namespace IPA.Config.Stores.Converters
/// the dictionary to serialize
/// the object that owns the dictionary
/// the dictionary serialized as a
- public override Value ToValue(IDictionary obj, object parent)
- => Value.From(obj.Select(p => new KeyValuePair(p.Key, BaseConverter.ToValue(p.Value, parent))));
+ public override Value? ToValue(IDictionary? obj, object parent)
+ => Value.From(obj.Select(p => new KeyValuePair(p.Key, BaseConverter.ToValue(p.Value, parent))));
}
///
@@ -373,7 +374,7 @@ namespace IPA.Config.Stores.Converters
/// A converter for instances of .
///
/// the value type of the dictionary
- public class DictionaryConverter : ValueConverter>
+ public class DictionaryConverter : ValueConverter>
{
///
/// Gets the converter for the dictionary's value type.
@@ -397,7 +398,7 @@ namespace IPA.Config.Stores.Converters
/// the to convert
/// the parent that will own the resulting object
/// the deserialized dictionary
- public override Dictionary FromValue(Value value, object parent)
+ public override Dictionary FromValue(Value? value, object parent)
=> (value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
?.ToDictionary(p => p.Key, p => p.val)
?? throw new ArgumentException("Value not a map", nameof(value));
@@ -408,8 +409,8 @@ namespace IPA.Config.Stores.Converters
/// the dictionary to serialize
/// the object that owns the dictionary
/// the dictionary serialized as a
- public override Value ToValue(Dictionary obj, object parent)
- => Value.From(obj.Select(p => new KeyValuePair(p.Key, BaseConverter.ToValue(p.Value, parent))));
+ public override Value? ToValue(Dictionary? obj, object parent)
+ => Value.From(obj?.Select(p => new KeyValuePair(p.Key, BaseConverter.ToValue(p.Value, parent))));
}
///
@@ -433,7 +434,7 @@ namespace IPA.Config.Stores.Converters
/// A converter for instances of .
///
/// the value type of the dictionary
- public class IReadOnlyDictionaryConverter : ValueConverter>
+ public class IReadOnlyDictionaryConverter : ValueConverter>
{
///
/// Gets the converter for the dictionary's value type.
@@ -457,7 +458,7 @@ namespace IPA.Config.Stores.Converters
/// the to convert
/// the parent that will own the resulting object
/// the deserialized dictionary
- public override IReadOnlyDictionary FromValue(Value value, object parent)
+ public override IReadOnlyDictionary FromValue(Value? value, object parent)
=> (value as Map)?.Select(kvp => (kvp.Key, val: BaseConverter.FromValue(kvp.Value, parent)))
?.ToDictionary(p => p.Key, p => p.val)
?? throw new ArgumentException("Value not a map", nameof(value));
@@ -468,8 +469,8 @@ namespace IPA.Config.Stores.Converters
/// the dictionary to serialize
/// the object that owns the dictionary
/// the dictionary serialized as a
- public override Value ToValue(IReadOnlyDictionary obj, object parent)
- => Value.From(obj.Select(p => new KeyValuePair(p.Key, BaseConverter.ToValue(p.Value, parent))));
+ public override Value? ToValue(IReadOnlyDictionary? obj, object parent)
+ => Value.From(obj?.Select(p => new KeyValuePair(p.Key, BaseConverter.ToValue(p.Value, parent))));
}
///
@@ -500,7 +501,7 @@ namespace IPA.Config.Stores.Converters
/// the object which will own the created object
/// the deserialized Color object
/// if is not a node or couldn't be parsed into a Color object
- public override Color FromValue(Value value, object parent)
+ public override Color FromValue(Value? value, object parent)
{
if (value is Text t)
{
@@ -526,146 +527,146 @@ namespace IPA.Config.Stores.Converters
internal class StringConverter : ValueConverter
{
- public override string FromValue(Value value, object parent)
+ public override string? FromValue(Value? value, object parent)
=> (value as Text)?.Value;
- public override Value ToValue(string obj, object parent)
+ public override Value? ToValue(string? obj, object parent)
=> Value.From(obj);
}
internal class CharConverter : ValueConverter
{
- public override char FromValue(Value value, object parent)
+ public override char FromValue(Value? value, object parent)
=> (value as Text)?.Value[0]
?? throw new ArgumentException("Value not a text node", nameof(value)); // can throw nullptr
- public override Value ToValue(char obj, object parent)
+ public override Value? ToValue(char obj, object parent)
=> Value.From(char.ToString(obj));
}
internal class LongConverter : ValueConverter
{
- public override long FromValue(Value value, object parent)
+ public override long FromValue(Value? value, object parent)
=> Converter.IntValue(value)
?? throw new ArgumentException("Value not a numeric value", nameof(value));
- public override Value ToValue(long obj, object parent)
+ public override Value? ToValue(long obj, object parent)
=> Value.From(obj);
}
internal class ULongConverter : ValueConverter
{
- public override ulong FromValue(Value value, object parent)
+ public override ulong FromValue(Value? value, object parent)
=> (ulong)(Converter.FloatValue(value)
?? throw new ArgumentException("Value not a numeric value", nameof(value)));
- public override Value ToValue(ulong obj, object parent)
+ public override Value? ToValue(ulong obj, object parent)
=> Value.From(obj);
}
internal class IntPtrConverter : ValueConverter
{
- public override IntPtr FromValue(Value value, object parent)
+ public override IntPtr FromValue(Value? value, object parent)
=> (IntPtr)Converter.Default.FromValue(value, parent);
- public override Value ToValue(IntPtr obj, object parent)
+ public override Value? ToValue(IntPtr obj, object parent)
=> Value.From((long)obj);
}
internal class UIntPtrConverter : ValueConverter
{
- public override UIntPtr FromValue(Value value, object parent)
+ public override UIntPtr FromValue(Value? value, object parent)
=> (UIntPtr)Converter.Default.FromValue(value, parent);
- public override Value ToValue(UIntPtr obj, object parent)
+ public override Value? ToValue(UIntPtr obj, object parent)
=> Value.From((decimal)obj);
}
internal class IntConverter : ValueConverter
{
- public override int FromValue(Value value, object parent)
+ public override int FromValue(Value? value, object parent)
=> (int)Converter.Default.FromValue(value, parent);
- public override Value ToValue(int obj, object parent)
+ public override Value? ToValue(int obj, object parent)
=> Value.From(obj);
}
internal class UIntConverter : ValueConverter
{
- public override uint FromValue(Value value, object parent)
+ public override uint FromValue(Value? value, object parent)
=> (uint)Converter.Default.FromValue(value, parent);
- public override Value ToValue(uint obj, object parent)
+ public override Value? ToValue(uint obj, object parent)
=> Value.From(obj);
}
internal class ShortConverter : ValueConverter
{
- public override short FromValue(Value value, object parent)
+ public override short FromValue(Value? value, object parent)
=> (short)Converter.Default.FromValue(value, parent);
- public override Value ToValue(short obj, object parent)
+ public override Value? ToValue(short obj, object parent)
=> Value.From(obj);
}
internal class UShortConverter : ValueConverter
{
- public override ushort FromValue(Value value, object parent)
+ public override ushort FromValue(Value? value, object parent)
=> (ushort)Converter.Default.FromValue(value, parent);
- public override Value ToValue(ushort obj, object parent)
+ public override Value? ToValue(ushort obj, object parent)
=> Value.From(obj);
}
internal class ByteConverter : ValueConverter
{
- public override byte FromValue(Value value, object parent)
+ public override byte FromValue(Value? value, object parent)
=> (byte)Converter.Default.FromValue(value, parent);
- public override Value ToValue(byte obj, object parent)
+ public override Value? ToValue(byte obj, object parent)
=> Value.From(obj);
}
internal class SByteConverter : ValueConverter
{
- public override sbyte FromValue(Value value, object parent)
+ public override sbyte FromValue(Value? value, object parent)
=> (sbyte)Converter.Default.FromValue(value, parent);
- public override Value ToValue(sbyte obj, object parent)
+ public override Value? ToValue(sbyte obj, object parent)
=> Value.From(obj);
}
internal class DecimalConverter : ValueConverter
{
- public override decimal FromValue(Value value, object parent)
+ public override decimal FromValue(Value? value, object parent)
=> Converter.FloatValue(value) ?? throw new ArgumentException("Value not a numeric value", nameof(value));
- public override Value ToValue(decimal obj, object parent)
+ public override Value? ToValue(decimal obj, object parent)
=> Value.From(obj);
}
internal class FloatConverter : ValueConverter
{
- public override float FromValue(Value value, object parent)
+ public override float FromValue(Value? value, object parent)
=> (float)Converter.Default.FromValue(value, parent);
- public override Value ToValue(float obj, object parent)
+ public override Value? ToValue(float obj, object parent)
=> Value.From((decimal)obj);
}
internal class DoubleConverter : ValueConverter
{
- public override double FromValue(Value value, object parent)
+ public override double FromValue(Value? value, object parent)
=> (double)Converter.Default.FromValue(value, parent);
- public override Value ToValue(double obj, object parent)
+ public override Value? ToValue(double obj, object parent)
=> Value.From((decimal)obj);
}
internal class BooleanConverter : ValueConverter
{
- public override bool FromValue(Value value, object parent)
+ public override bool FromValue(Value? value, object parent)
=> (value as Boolean)?.Value ?? throw new ArgumentException("Value not a Boolean", nameof(value));
- public override Value ToValue(bool obj, object parent)
+ public override Value? ToValue(bool obj, object parent)
=> Value.From(obj);
}
internal class DateTimeConverter : ValueConverter
{
- public override DateTime FromValue(Value value, object parent)
+ public override DateTime FromValue(Value? value, object parent)
{
- if (!(value is Text text))
+ if (value is not Text text)
{
throw new ArgumentException("Value is not of type Text", nameof(value));
}
@@ -678,14 +679,14 @@ namespace IPA.Config.Stores.Converters
throw new ArgumentException($"Parsing failed, {text.Value}");
}
- public override Value ToValue(DateTime obj, object parent) => Value.Text(obj.ToString("O"));
+ public override Value? ToValue(DateTime obj, object parent) => Value.Text(obj.ToString("O"));
}
internal class DateTimeOffsetConverter : ValueConverter
{
- public override DateTimeOffset FromValue(Value value, object parent)
+ public override DateTimeOffset FromValue(Value? value, object parent)
{
- if (!(value is Text text))
+ if (value is not Text text)
{
throw new ArgumentException("Value is not of type Text", nameof(value));
}
@@ -703,9 +704,9 @@ namespace IPA.Config.Stores.Converters
internal class TimeSpanConverter : ValueConverter
{
- public override TimeSpan FromValue(Value value, object parent)
+ public override TimeSpan FromValue(Value? value, object parent)
{
- if (!(value is Text text))
+ if (value is not Text text)
{
throw new ArgumentException("Value is not of type Text", nameof(value));
}
@@ -718,6 +719,6 @@ namespace IPA.Config.Stores.Converters
throw new ArgumentException($"Parsing failed, {text.Value}");
}
- public override Value ToValue(TimeSpan obj, object parent) => Value.Text(obj.ToString());
+ public override Value? ToValue(TimeSpan obj, object parent) => Value.Text(obj.ToString());
}
}
diff --git a/IPA.Loader/Config/Stores/CustomObjectConverter.cs b/IPA.Loader/Config/Stores/CustomObjectConverter.cs
index be881cc7..10787398 100644
--- a/IPA.Loader/Config/Stores/CustomObjectConverter.cs
+++ b/IPA.Loader/Config/Stores/CustomObjectConverter.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Data;
+#nullable enable
+using IPA.Config.Data;
using System;
namespace IPA.Config.Stores.Converters
@@ -12,24 +13,26 @@ namespace IPA.Config.Stores.Converters
{
private interface IImpl
{
- T FromValue(Value value, object parent);
- Value ToValue(T obj, object parent);
+ T? FromValue(Value? value, object parent);
+ Value? ToValue(T? obj, object parent);
}
private class Impl : IImpl where U : class, GeneratedStoreImpl.IGeneratedStore, T
{
private static readonly GeneratedStoreImpl.GeneratedStoreCreator creator = GeneratedStoreImpl.GetCreator(typeof(T));
- private static U Create(GeneratedStoreImpl.IGeneratedStore parent)
- => creator(parent) as U;
+ private static U Create(GeneratedStoreImpl.IGeneratedStore? parent)
+ => (U)creator(parent);
- public T FromValue(Value value, object parent)
+ public T? FromValue(Value? value, object parent)
{ // lots of casting here, but it works i promise (probably) (parent can be a non-IGeneratedStore, however it won't necessarily behave then)
+ if (value is null) return null;
var obj = Create(parent as GeneratedStoreImpl.IGeneratedStore);
obj.Deserialize(value);
return obj;
}
- public Value ToValue(T obj, object parent)
+ public Value? ToValue(T? obj, object parent)
{
+ if (obj is null) return null;
if (obj is GeneratedStoreImpl.IGeneratedStore store)
return store.Serialize();
else
@@ -51,7 +54,7 @@ namespace IPA.Config.Stores.Converters
/// the parent object that will own the deserialized value
/// the deserialized value
///
- public static T Deserialize(Value value, object parent)
+ public static T? Deserialize(Value? value, object parent)
=> impl.FromValue(value, parent);
///
@@ -61,7 +64,7 @@ namespace IPA.Config.Stores.Converters
/// the parent object that owns
/// the tree that represents
///
- public static Value Serialize(T obj, object parent)
+ public static Value? Serialize(T? obj, object parent)
=> impl.ToValue(obj, parent);
///
@@ -71,7 +74,7 @@ namespace IPA.Config.Stores.Converters
/// the parent object that will own the deserialized value
/// the deserialized value
///
- public override T FromValue(Value value, object parent)
+ public override T? FromValue(Value? value, object parent)
=> Deserialize(value, parent);
///
@@ -81,7 +84,7 @@ namespace IPA.Config.Stores.Converters
/// the parent object that owns
/// the tree that represents
///
- public override Value ToValue(T obj, object parent)
+ public override Value? ToValue(T? obj, object parent)
=> Serialize(obj, parent);
}
@@ -104,7 +107,7 @@ namespace IPA.Config.Stores.Converters
/// the parent object that will own the deserialized value
/// the deserialized value
///
- public static T Deserialize(Value value, object parent)
+ public static T Deserialize(Value? value, object parent)
=> deserialize(value, parent);
///
@@ -123,7 +126,7 @@ namespace IPA.Config.Stores.Converters
/// the parent object that will own the deserialized value
/// the deserialized value
///
- public override T FromValue(Value value, object parent)
+ public override T FromValue(Value? value, object parent)
=> Deserialize(value, parent);
///
@@ -133,7 +136,7 @@ namespace IPA.Config.Stores.Converters
/// the parent object that owns
/// the tree that represents
///
- public override Value ToValue(T obj, object parent)
+ public override Value? ToValue(T obj, object parent)
=> Serialize(obj);
}
diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/ConversionDelegates.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/ConversionDelegates.cs
index 1ad9fd12..dc7f5ea9 100644
--- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/ConversionDelegates.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/ConversionDelegates.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Data;
+#nullable enable
+using IPA.Config.Data;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -13,12 +14,12 @@ namespace IPA.Config.Stores
{
internal delegate Value SerializeObject(T obj);
- internal delegate T DeserializeObject(Value val, object parent);
+ internal delegate T DeserializeObject(Value? val, object parent);
private static class DelegateStore
{
- public static SerializeObject Serialize;
- public static DeserializeObject Deserialize;
+ public static SerializeObject? Serialize;
+ public static DeserializeObject? Deserialize;
}
internal static SerializeObject GetSerializerDelegate()
diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/Correction.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/Correction.cs
index 15d54c97..b59bf7d0 100644
--- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/Correction.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/Correction.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Data;
+#nullable enable
+using IPA.Config.Data;
using IPA.Config.Stores.Attributes;
using IPA.Logging;
using System;
diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/Deserialization.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/Deserialization.cs
index 7f0bdffe..ab424717 100644
--- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/Deserialization.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/Deserialization.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Data;
+#nullable enable
+using IPA.Config.Data;
using IPA.Logging;
using System;
using System.Collections;
@@ -43,6 +44,7 @@ namespace IPA.Config.Stores
private static void EmitDeserializeNullable(ILGenerator il, SerializedMemberInfo member, Type expected, LocalAllocator GetLocal,
Action thisarg, Action parentobj)
{
+ if (!member.IsNullable) throw new InvalidOperationException("EmitDeserializeNullable called for non-nullable!");
thisarg ??= il => il.Emit(OpCodes.Ldarg_0);
parentobj ??= thisarg;
EmitDeserializeValue(il, member, member.NullableWrappedType, expected, GetLocal, thisarg, parentobj);
@@ -161,6 +163,9 @@ namespace IPA.Config.Stores
private static void EmitDeserializeConverter(ILGenerator il, SerializedMemberInfo member, Label nextLabel, LocalAllocator GetLocal,
Action thisobj, Action parentobj)
{
+ if (!member.HasConverter)
+ throw new InvalidOperationException("EmitDeserializeConverter called for member without converter");
+
using var stlocal = GetLocal.Allocate(typeof(Value));
using var valLocal = GetLocal.Allocate(member.Type);
diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/GeneratedStoreImpl.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/GeneratedStoreImpl.cs
index c069905f..7efa987a 100644
--- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/GeneratedStoreImpl.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/GeneratedStoreImpl.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Data;
+#nullable enable
+using IPA.Config.Data;
using IPA.Config.Stores.Attributes;
using IPA.Logging;
using System;
@@ -36,13 +37,12 @@ namespace IPA.Config.Stores
private static readonly MethodInfo CreateGParent =
typeof(GeneratedStoreImpl).GetMethod(nameof(Create), BindingFlags.NonPublic | BindingFlags.Static, null,
CallingConventions.Any, new[] { typeof(IGeneratedStore) }, Array.Empty());
- internal static T Create(IGeneratedStore parent) where T : class => (T)Create(typeof(T), parent);
+ internal static T Create(IGeneratedStore? parent) where T : class => (T)Create(typeof(T), parent);
- private static IConfigStore Create(Type type, IGeneratedStore parent)
+ private static IConfigStore Create(Type type, IGeneratedStore? parent)
=> GetCreator(type)(parent);
- private static readonly SingleCreationValueCache generatedCreators
- = new SingleCreationValueCache();
+ private static readonly SingleCreationValueCache generatedCreators = new();
private static (GeneratedStoreCreator ctor, Type type) GetCreatorAndGeneratedType(Type t)
=> generatedCreators.GetOrAdd(t, MakeCreator);
@@ -55,7 +55,7 @@ namespace IPA.Config.Stores
internal const string GeneratedAssemblyName = "IPA.Config.Generated";
- private static AssemblyBuilder assembly = null;
+ private static AssemblyBuilder? assembly;
private static AssemblyBuilder Assembly
{
get
@@ -75,7 +75,7 @@ namespace IPA.Config.Stores
Assembly.Save(file);
}
- private static ModuleBuilder module = null;
+ private static ModuleBuilder? module;
private static ModuleBuilder Module
{
get
@@ -88,7 +88,7 @@ namespace IPA.Config.Stores
}
// TODO: does this need to be a SingleCreationValueCache or similar?
- private static readonly Dictionary> TypeRequiredConverters = new Dictionary>();
+ private static readonly Dictionary> TypeRequiredConverters = new();
private static void CreateAndInitializeConvertersFor(Type type, IEnumerable structure)
{
if (!TypeRequiredConverters.TryGetValue(type, out var converters))
@@ -96,7 +96,8 @@ namespace IPA.Config.Stores
var converterFieldType = Module.DefineType($"{type.FullName}",
TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.AnsiClass); // a static class
- var uniqueConverterTypes = structure.Where(m => m.HasConverter).Select(m => m.Converter).Distinct().ToArray();
+ var uniqueConverterTypes = structure.Where(m => m.HasConverter)
+ .Select(m => m.Converter).NonNull().Distinct().ToArray();
converters = new Dictionary(uniqueConverterTypes.Length);
foreach (var convType in uniqueConverterTypes)
@@ -122,11 +123,14 @@ namespace IPA.Config.Stores
TypeRequiredConverters.Add(type, converters);
- converterFieldType.CreateType();
+ _ = converterFieldType.CreateType();
}
- foreach (var member in structure.Where(m => m.HasConverter))
+ foreach (var member in structure)
+ {
+ if (!member.HasConverter) continue;
member.ConverterField = converters[member.Converter];
+ }
}
}
}
diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/IGeneratedStore.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/IGeneratedStore.cs
index 350ef742..dc323833 100644
--- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/IGeneratedStore.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/IGeneratedStore.cs
@@ -1,4 +1,5 @@
-using IPA.Logging;
+#nullable enable
+using IPA.Logging;
using System;
using System.Collections.Generic;
using System.Reflection;
@@ -42,27 +43,27 @@ namespace IPA.Config.Stores
internal class Impl : IConfigStore
{
private readonly IGeneratedStore generated;
- private long enteredTransactions = 0;
+ private long enteredTransactions;
internal static ConstructorInfo Ctor = typeof(Impl).GetConstructor(new[] { typeof(IGeneratedStore) });
public Impl(IGeneratedStore store) => generated = store;
- private readonly AutoResetEvent resetEvent = new AutoResetEvent(false);
+ private readonly AutoResetEvent resetEvent = new(false);
public WaitHandle SyncObject => resetEvent;
- public static WaitHandle ImplGetSyncObject(IGeneratedStore s) => FindImpl(s).SyncObject;
+ public static WaitHandle? ImplGetSyncObject(IGeneratedStore s) => FindImpl(s)?.SyncObject;
internal static MethodInfo ImplGetSyncObjectMethod = typeof(Impl).GetMethod(nameof(ImplGetSyncObject));
- public ReaderWriterLockSlim WriteSyncObject { get; } = new ReaderWriterLockSlim();
- public static ReaderWriterLockSlim ImplGetWriteSyncObject(IGeneratedStore s) => FindImpl(s)?.WriteSyncObject;
+ public ReaderWriterLockSlim WriteSyncObject { get; } = new();
+ public static ReaderWriterLockSlim? ImplGetWriteSyncObject(IGeneratedStore s) => FindImpl(s)?.WriteSyncObject;
internal static MethodInfo ImplGetWriteSyncObjectMethod = typeof(Impl).GetMethod(nameof(ImplGetWriteSyncObject));
internal static MethodInfo ImplSignalChangedMethod = typeof(Impl).GetMethod(nameof(ImplSignalChanged));
- public static void ImplSignalChanged(IGeneratedStore s) => FindImpl(s).SignalChanged();
+ public static void ImplSignalChanged(IGeneratedStore s) => FindImpl(s)?.SignalChanged();
public void SignalChanged()
{
try
{
- resetEvent.Set();
+ _ = resetEvent.Set();
}
catch (ObjectDisposedException e)
{
@@ -72,11 +73,11 @@ namespace IPA.Config.Stores
}
internal static MethodInfo ImplInvokeChangedMethod = typeof(Impl).GetMethod(nameof(ImplInvokeChanged));
- public static void ImplInvokeChanged(IGeneratedStore s) => FindImpl(s).InvokeChanged();
+ public static void ImplInvokeChanged(IGeneratedStore s) => FindImpl(s)?.InvokeChanged();
public void InvokeChanged() => generated.Changed();
internal static MethodInfo ImplTakeReadMethod = typeof(Impl).GetMethod(nameof(ImplTakeRead));
- public static void ImplTakeRead(IGeneratedStore s) => FindImpl(s).TakeRead();
+ public static void ImplTakeRead(IGeneratedStore s) => FindImpl(s)?.TakeRead();
public void TakeRead()
{
if (!WriteSyncObject.IsWriteLockHeld)
@@ -84,7 +85,7 @@ namespace IPA.Config.Stores
}
internal static MethodInfo ImplReleaseReadMethod = typeof(Impl).GetMethod(nameof(ImplReleaseRead));
- public static void ImplReleaseRead(IGeneratedStore s) => FindImpl(s).ReleaseRead();
+ public static void ImplReleaseRead(IGeneratedStore s) => FindImpl(s)?.ReleaseRead();
public void ReleaseRead()
{
if (!WriteSyncObject.IsWriteLockHeld)
@@ -92,24 +93,24 @@ namespace IPA.Config.Stores
}
internal static MethodInfo ImplTakeWriteMethod = typeof(Impl).GetMethod(nameof(ImplTakeWrite));
- public static void ImplTakeWrite(IGeneratedStore s) => FindImpl(s).TakeWrite();
+ public static void ImplTakeWrite(IGeneratedStore s) => FindImpl(s)?.TakeWrite();
public void TakeWrite() => WriteSyncObject.EnterWriteLock();
internal static MethodInfo ImplReleaseWriteMethod = typeof(Impl).GetMethod(nameof(ImplReleaseWrite));
- public static void ImplReleaseWrite(IGeneratedStore s) => FindImpl(s).ReleaseWrite();
+ public static void ImplReleaseWrite(IGeneratedStore s) => FindImpl(s)?.ReleaseWrite();
public void ReleaseWrite() => WriteSyncObject.ExitWriteLock();
internal static MethodInfo ImplChangeTransactionMethod = typeof(Impl).GetMethod(nameof(ImplChangeTransaction));
- public static IDisposable ImplChangeTransaction(IGeneratedStore s, IDisposable nest) => FindImpl(s).ChangeTransaction(nest);
+ public static IDisposable? ImplChangeTransaction(IGeneratedStore s, IDisposable nest) => FindImpl(s)?.ChangeTransaction(nest);
// TODO: improve trasactionals so they don't always save in every case
public IDisposable ChangeTransaction(IDisposable nest, bool takeWrite = true)
=> GetFreeTransaction().InitWith(this, nest, takeWrite && !WriteSyncObject.IsWriteLockHeld);
- private ChangeTransactionObj GetFreeTransaction()
+ private static ChangeTransactionObj GetFreeTransaction()
=> freeTransactionObjs.Count > 0 ? freeTransactionObjs.Pop()
: new ChangeTransactionObj();
// TODO: maybe sometimes clean this?
- private static readonly Stack freeTransactionObjs = new Stack();
+ private static readonly Stack freeTransactionObjs = new();
private sealed class ChangeTransactionObj : IDisposable
{
@@ -148,7 +149,7 @@ namespace IPA.Config.Stores
try
{
if (data.ownsWrite)
- data.impl.ReleaseWrite();
+ data.impl?.ReleaseWrite();
}
catch
{
@@ -163,14 +164,14 @@ namespace IPA.Config.Stores
~ChangeTransactionObj() => Dispose(false);
}
- public static Impl FindImpl(IGeneratedStore store)
+ public static Impl? FindImpl(IGeneratedStore store)
{
while (store?.Parent != null) store = store.Parent; // walk to the top of the tree
return store?.Impl;
}
internal static MethodInfo ImplReadFromMethod = typeof(Impl).GetMethod(nameof(ImplReadFrom));
- public static void ImplReadFrom(IGeneratedStore s, ConfigProvider provider) => FindImpl(s).ReadFrom(provider);
+ public static void ImplReadFrom(IGeneratedStore s, ConfigProvider provider) => FindImpl(s)?.ReadFrom(provider);
public void ReadFrom(ConfigProvider provider)
{
Logger.config.Debug($"Generated impl ReadFrom {generated.GetType()}");
@@ -183,7 +184,7 @@ namespace IPA.Config.Stores
}
internal static MethodInfo ImplWriteToMethod = typeof(Impl).GetMethod(nameof(ImplWriteTo));
- public static void ImplWriteTo(IGeneratedStore s, ConfigProvider provider) => FindImpl(s).WriteTo(provider);
+ public static void ImplWriteTo(IGeneratedStore s, ConfigProvider provider) => FindImpl(s)?.WriteTo(provider);
public void WriteTo(ConfigProvider provider)
{
Logger.config.Debug($"Generated impl WriteTo {generated.GetType()}");
diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs
index d9248c21..c80ef1ea 100644
--- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Data;
+#nullable enable
+using IPA.Config.Data;
using IPA.Config.Stores.Attributes;
using IPA.Logging;
using System;
@@ -21,7 +22,7 @@ namespace IPA.Config.Stores
internal static partial class GeneratedStoreImpl
{
- internal delegate IConfigStore GeneratedStoreCreator(IGeneratedStore parent);
+ internal delegate IConfigStore GeneratedStoreCreator(IGeneratedStore? parent);
private static void GetMethodThis(ILGenerator il) => il.Emit(OpCodes.Ldarg_0);
private static (GeneratedStoreCreator ctor, Type type) MakeCreator(Type type)
@@ -109,7 +110,7 @@ namespace IPA.Config.Stores
const MethodAttributes virtualMemberMethod = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.Final;
#region INotifyPropertyChanged
- MethodBuilder notifyChanged = null;
+ MethodBuilder? notifyChanged = null;
if (isINotifyPropertyChanged || hasNotifyAttribute)
{
// we don't actually want to notify if the base class implements it
@@ -639,7 +640,7 @@ namespace IPA.Config.Stores
#region Members
foreach (var member in structure.Where(m => m.IsVirtual))
{ // IsVirtual implies !IsField
- var prop = member.Member as PropertyInfo;
+ var prop = (PropertyInfo)member.Member;
var get = prop.GetGetMethod(true);
var set = prop.GetSetMethod(true);
diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/ObjectStructure.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/ObjectStructure.cs
index 86384804..904ee261 100644
--- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/ObjectStructure.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/ObjectStructure.cs
@@ -1,10 +1,12 @@
-using IPA.Config.Stores.Attributes;
+#nullable enable
+using IPA.Config.Stores.Attributes;
using IPA.Config.Stores.Converters;
using IPA.Logging;
using IPA.Utilities;
using IPA.Utilities.Async;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text;
@@ -20,23 +22,25 @@ namespace IPA.Config.Stores
{
private class SerializedMemberInfo
{
- public string Name;
- public MemberInfo Member;
- public Type Type;
+ public string Name = null!;
+ public MemberInfo Member = null!;
+ public Type Type = null!;
public bool AllowNull;
public bool IsVirtual;
public bool IsField;
- public bool IsNullable; // signifies whether this is a Nullable
+ [MemberNotNullWhen(true, nameof(NullableWrappedType))]
+ public bool IsNullable { get; set; } // signifies whether this is a Nullable
- public bool HasConverter;
- public bool IsGenericConverter; // used so we can call directly to the generic version if it is
- public Type Converter;
- public Type ConverterBase;
- public Type ConverterTarget;
- public FieldInfo ConverterField;
+ [MemberNotNullWhen(true, nameof(Converter), nameof(ConverterBase))]
+ public bool HasConverter { get; set; }
+ public bool IsGenericConverter { get; set; } // used so we can call directly to the generic version if it is
+ public Type? Converter;
+ public Type? ConverterBase;
+ public Type? ConverterTarget;
+ public FieldInfo? ConverterField;
// invalid for objects with IsNullable false
- public Type NullableWrappedType => Nullable.GetUnderlyingType(Type);
+ public Type? NullableWrappedType => Nullable.GetUnderlyingType(Type);
// invalid for objects with IsNullable false
public PropertyInfo Nullable_HasValue => Type.GetProperty(nameof(Nullable.HasValue));
// invalid for objects with IsNullable false
@@ -73,6 +77,8 @@ namespace IPA.Config.Stores
{
if (converterAttr.UseDefaultConverterForType)
converterAttr = new UseConverterAttribute(Converter.GetDefaultConverterType(member.Type));
+ if (converterAttr.UseDefaultConverterForType)
+ throw new InvalidOperationException("How did we get here?");
member.Converter = converterAttr.ConverterType;
member.IsGenericConverter = converterAttr.IsGenericConverter;
@@ -100,7 +106,7 @@ namespace IPA.Config.Stores
{
try
{
- var conv = Activator.CreateInstance(converterAttr.ConverterType) as IValueConverter;
+ var conv = (IValueConverter)Activator.CreateInstance(converterAttr.ConverterType);
targetType = conv.Type;
}
catch
@@ -128,8 +134,7 @@ namespace IPA.Config.Stores
return true;
}
- private static readonly SingleCreationValueCache objectStructureCache
- = new SingleCreationValueCache();
+ private static readonly SingleCreationValueCache objectStructureCache = new();
private static IEnumerable ReadObjectMembers(Type type)
=> objectStructureCache.GetOrAdd(type, t => ReadObjectMembersInternal(type).ToArray());
diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/Serialization.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/Serialization.cs
index cea03460..b1cd6138 100644
--- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/Serialization.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/Serialization.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Data;
+#nullable enable
+using IPA.Config.Data;
using IPA.Logging;
using System;
using System.Collections.Generic;
diff --git a/IPA.Loader/Config/Stores/GeneratedStorePublicInterface.cs b/IPA.Loader/Config/Stores/GeneratedStorePublicInterface.cs
index 7ece8174..c768c1be 100644
--- a/IPA.Loader/Config/Stores/GeneratedStorePublicInterface.cs
+++ b/IPA.Loader/Config/Stores/GeneratedStorePublicInterface.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Stores.Attributes;
+#nullable enable
+using IPA.Config.Stores.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/IPA.Loader/Config/Stores/ValueConverter.cs b/IPA.Loader/Config/Stores/ValueConverter.cs
index 8be1f300..68cec79e 100644
--- a/IPA.Loader/Config/Stores/ValueConverter.cs
+++ b/IPA.Loader/Config/Stores/ValueConverter.cs
@@ -1,4 +1,5 @@
-using IPA.Config.Data;
+#nullable enable
+using IPA.Config.Data;
using System;
namespace IPA.Config.Stores
@@ -31,14 +32,14 @@ namespace IPA.Config.Stores
/// the object to convert
/// the owning object of
/// a representation of as a structure
- Value ToValue(object obj, object parent);
+ Value? ToValue(object? obj, object parent);
///
/// Converts the given to the object type handled by this converter.
///
/// the to deserialize
/// the object that will own the result
/// the deserialized object
- object FromValue(Value value, object parent);
+ object? FromValue(Value? value, object parent);
///
/// Gets the type that this handles.
///
@@ -59,7 +60,7 @@ namespace IPA.Config.Stores
/// the owning object of
/// a representation of as a structure
///
- public abstract Value ToValue(T obj, object parent);
+ public abstract Value? ToValue(T? obj, object parent);
///
/// Converts the given to the object type handled by this converter.
///
@@ -67,10 +68,10 @@ namespace IPA.Config.Stores
/// the object that will own the result
/// the deserialized object
///
- public abstract T FromValue(Value value, object parent);
+ public abstract T? FromValue(Value? value, object parent);
- Value IValueConverter.ToValue(object obj, object parent) => ToValue((T)obj, parent);
- object IValueConverter.FromValue(Value value, object parent) => FromValue(value, parent);
+ Value? IValueConverter.ToValue(object? obj, object parent) => ToValue((T?)obj, parent);
+ object? IValueConverter.FromValue(Value? value, object parent) => FromValue(value, parent);
Type IValueConverter.Type => typeof(T);
}
}
diff --git a/IPA.Loader/Utilities/AlmostVersion.cs b/IPA.Loader/Utilities/AlmostVersion.cs
index 03ff5736..6b9c8111 100644
--- a/IPA.Loader/Utilities/AlmostVersion.cs
+++ b/IPA.Loader/Utilities/AlmostVersion.cs
@@ -305,15 +305,19 @@ namespace IPA.Utilities
/// the node to convert
/// the owner of the new object
///
- public override AlmostVersion FromValue(Value value, object parent)
- => new(Converter.Default.FromValue(value, parent));
+ public override AlmostVersion? FromValue(Value? value, object parent)
+ => Converter.Default.FromValue(value, parent) switch
+ {
+ { } v => new(v),
+ _ => null
+ };
///
/// Converts an to a node.
///
/// the to convert
/// the parent of
/// a node representing
- public override Value ToValue(AlmostVersion obj, object parent)
- => Value.From(obj.ToString());
+ public override Value? ToValue(AlmostVersion? obj, object parent)
+ => Value.From(obj?.ToString());
}
}
diff --git a/IPA/_Attributes.cs b/IPA/_Attributes.cs
deleted file mode 100644
index b56d00af..00000000
--- a/IPA/_Attributes.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-#if NET472
-namespace System.Diagnostics.CodeAnalysis
-{
- [AttributeUsage(AttributeTargets.Method, Inherited = false)]
- public sealed class DoesNotReturnAttribute : Attribute
- {
- public DoesNotReturnAttribute() { }
- }
-}
-#endif
\ No newline at end of file