Analyzer to check that notnullableflag is being properly used (#3569)

This commit is contained in:
Paul Ritter
2022-12-21 00:11:04 +01:00
committed by GitHub
parent a0b067a062
commit bafbdb6363
39 changed files with 338 additions and 132 deletions

View File

@@ -39,7 +39,7 @@ END TEMPLATE-->
### New features
*None yet*
* Serv4's notNullableOverride parameter is now enforced by analyzer. For more info, see [the docs](https://docs.spacestation14.io/en/engine/serialization).
### Bugfixes

View File

@@ -12,6 +12,11 @@ public static class Diagnostics
public const string IdUseGenericVariant = "RA0005";
public const string IdUseGenericVariantInvalidUsage = "RA0006";
public const string IdUseGenericVariantAttributeValueError = "RA0007";
public const string IdNotNullableFlagNotSet = "RA0008";
public const string IdInvalidNotNullableFlagValue = "RA0009";
public const string IdInvalidNotNullableFlagImplementation = "RA0010";
public const string IdInvalidNotNullableFlagType = "RA0011";
public const string IdNotNullableFlagValueType = "RA0012";
public static SuppressionDescriptor MeansImplicitAssignment =>
new SuppressionDescriptor("RADC1000", "CS0649", "Marked as implicitly assigned.");

View File

@@ -0,0 +1,171 @@
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
namespace Robust.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class NotNullableFlagAnalyzer : DiagnosticAnalyzer
{
private const string Attribute = "Robust.Shared.Analyzers.NotNullableFlagAttribute";
private static readonly DiagnosticDescriptor NotNullableNotSetRule = new (
Diagnostics.IdNotNullableFlagNotSet,
"Not Nullable Flag not set",
"Class type parameter {0} is not annotated as nullable and notNullableOverride is not set to true",
"Usage",
DiagnosticSeverity.Error,
true,
"Assign true to notNullableOverride or specify the type parameter as nullable.");
private static readonly DiagnosticDescriptor InvalidNotNullableValueRule = new (
Diagnostics.IdInvalidNotNullableFlagValue,
"Not Nullable Flag wrongfully set",
"Class type parameter {0} is annotated as nullable but notNullableOverride is set to true",
"Usage",
DiagnosticSeverity.Error,
true,
"Remove the true assignment to notNullableOverride or remove the nullable specifier of the type parameter.");
private static readonly DiagnosticDescriptor InvalidNotNullableImplementationRule = new (
Diagnostics.IdInvalidNotNullableFlagImplementation,
"Invalid NotNullable flag implementation.",
"NotNullable flag is either not typed as bool, or does not have a default value equaling false",
"Usage",
DiagnosticSeverity.Error,
true,
"Ensure that the notNullable flag is typed bool and has false set as a default value.");
private static readonly DiagnosticDescriptor InvalidNotNullableTypeRule = new (
Diagnostics.IdInvalidNotNullableFlagType,
"Failed to resolve type parameter",
"Failed to resolve type parameter \"{0}\".",
"Usage",
DiagnosticSeverity.Error,
true,
"Use nameof to avoid typos.");
private static readonly DiagnosticDescriptor NotNullableFlagValueTypeRule = new (
Diagnostics.IdNotNullableFlagValueType,
"NotNullable flag not supported for value types.",
"Value types as generic arguments are not supported for NotNullable flags",
"Usage",
DiagnosticSeverity.Error,
true,
"Nullable value types are distinct at runtime when inspected with reflection. Therefore they are not supported for NotNullable flags.");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
ImmutableArray.Create(
NotNullableNotSetRule,
InvalidNotNullableValueRule,
InvalidNotNullableImplementationRule,
InvalidNotNullableTypeRule,
NotNullableFlagValueTypeRule);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.EnableConcurrentExecution();
context.RegisterOperationAction(CheckNotNullableFlag, OperationKind.Invocation);
}
private bool TryGetTypeArgument(IMethodSymbol methodSymbol, string typeParamName, out ITypeSymbol typeArgument)
{
for (var index = 0; index < methodSymbol.TypeParameters.Length; index++)
{
if (methodSymbol.TypeParameters[index].Name != typeParamName)
continue;
typeArgument = methodSymbol.TypeArguments[index];
return true;
}
typeArgument = null;
return false;
}
private void CheckNotNullableFlag(OperationAnalysisContext context)
{
if (context.Operation is not IInvocationOperation invocationOperation || !invocationOperation.TargetMethod.IsGenericMethod)
return;
var attribute = context.Compilation.GetTypeByMetadataName(Attribute);
var @bool = context.Compilation.GetSpecialType(SpecialType.System_Boolean);
foreach (var argument in invocationOperation.Arguments)
{
if(argument.Parameter == null) continue;
foreach (var attributeData in argument.Parameter.GetAttributes())
{
if (!SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, attribute))
continue;
if (!SymbolEqualityComparer.Default.Equals(argument.Parameter.Type, @bool) ||
!argument.Parameter.HasExplicitDefaultValue ||
argument.Parameter.ExplicitDefaultValue as bool? != false)
{
context.ReportDiagnostic(Diagnostic.Create(
InvalidNotNullableImplementationRule,
argument.Parameter.Locations[0]));
break;
}
if (!TryGetTypeArgument(invocationOperation.TargetMethod,
attributeData.ConstructorArguments[0].Value as string, out var typeArgument))
{
context.ReportDiagnostic(Diagnostic.Create(
InvalidNotNullableTypeRule,
argument.Parameter.Locations[0],
attributeData.ConstructorArguments[0].Value as string));
break;
}
//until i find a way to implement it sanely, generic calls are exempt from this attribute
if(typeArgument is ITypeParameterSymbol) break;
//dont ask me why, argument.ConstantValue just straight up doesnt work.
//i still kept it in here as a fallback, incase it ever starts working again lol -<paul
var constantValue = (argument.Value as ILiteralOperation)?.ConstantValue ?? argument.ConstantValue;
if (typeArgument.IsValueType)
{
if (argument.ArgumentKind != ArgumentKind.DefaultValue)
{
//todo diagnostic only use for struct types
context.ReportDiagnostic(Diagnostic.Create(
NotNullableFlagValueTypeRule,
argument.Syntax.GetLocation()));
}
break;
}
if (typeArgument.NullableAnnotation == NullableAnnotation.None ||
(argument.ArgumentKind != ArgumentKind.DefaultValue && !constantValue.HasValue))
break;
var flagValue = argument.ArgumentKind != ArgumentKind.DefaultValue ||
constantValue.Value as bool? == true;
var nullable = typeArgument.NullableAnnotation == NullableAnnotation.Annotated;
if (nullable && flagValue)
{
context.ReportDiagnostic(Diagnostic.Create(InvalidNotNullableValueRule,
argument.Syntax.GetLocation(),
typeArgument));
}
else if (!nullable && !flagValue)
{
context.ReportDiagnostic(Diagnostic.Create(NotNullableNotSetRule,
argument.Syntax.GetLocation(),
typeArgument));
}
break;
}
}
}
}

View File

@@ -11,6 +11,11 @@
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<!-- Needed for NotNullableFlagAnalyzer. -->
<Compile Include="..\Robust.Shared\Analyzers\NotNullableFlagAttribute.cs" />
</ItemGroup>
<ItemGroup>
<!-- Needed for FriendAnalyzer. -->
<Compile Include="..\Robust.Shared\Analyzers\AccessAttribute.cs" />

View File

@@ -27,7 +27,7 @@ namespace Robust.Benchmarks.Serialization.Copy
var seedMapping = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>().Cast<MappingDataNode>(0);
Seed = SerializationManager.Read<SeedDataDefinition>(seedMapping);
Seed = SerializationManager.Read<SeedDataDefinition>(seedMapping, notNullableOverride: true);
}
private const string String = "ABC";
@@ -45,7 +45,7 @@ namespace Robust.Benchmarks.Serialization.Copy
[Benchmark]
public string? CreateCopyString()
{
return SerializationManager.CreateCopy(String);
return SerializationManager.CreateCopy(String, notNullableOverride: true);
}
[Benchmark]
@@ -57,13 +57,13 @@ namespace Robust.Benchmarks.Serialization.Copy
[Benchmark]
public DataDefinitionWithString? CreateCopyDataDefinitionWithString()
{
return SerializationManager.CreateCopy(DataDefinitionWithString);
return SerializationManager.CreateCopy(DataDefinitionWithString, notNullableOverride: true);
}
[Benchmark]
public SeedDataDefinition? CreateCopySeedDataDefinition()
{
return SerializationManager.CreateCopy(Seed);
return SerializationManager.CreateCopy(Seed, notNullableOverride: true);
}
[Benchmark]

View File

@@ -43,7 +43,7 @@ namespace Robust.Benchmarks.Serialization.Read
[Benchmark]
public string ReadString()
{
return SerializationManager.Read<string>(StringNode);
return SerializationManager.Read<string>(StringNode, notNullableOverride: true);
}
[Benchmark]
@@ -55,13 +55,13 @@ namespace Robust.Benchmarks.Serialization.Read
[Benchmark]
public DataDefinitionWithString ReadDataDefinitionWithString()
{
return SerializationManager.Read<DataDefinitionWithString>(StringDataDefNode);
return SerializationManager.Read<DataDefinitionWithString>(StringDataDefNode, notNullableOverride: true);
}
[Benchmark]
public SeedDataDefinition ReadSeedDataDefinition()
{
return SerializationManager.Read<SeedDataDefinition>(SeedNode);
return SerializationManager.Read<SeedDataDefinition>(SeedNode, notNullableOverride: true);
}
[Benchmark]

View File

@@ -46,84 +46,84 @@ namespace Robust.Benchmarks.Serialization
[BenchmarkCategory("read")]
public string[]? ReadEmptyString()
{
return SerializationManager.Read<string[]>(EmptyNode);
return SerializationManager.Read<string[]>(EmptyNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public string[]? ReadOneString()
{
return SerializationManager.Read<string[]>(OneIntNode);
return SerializationManager.Read<string[]>(OneIntNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public string[]? ReadTenStrings()
{
return SerializationManager.Read<string[]>(TenIntsNode);
return SerializationManager.Read<string[]>(TenIntsNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public int[]? ReadEmptyInt()
{
return SerializationManager.Read<int[]>(EmptyNode);
return SerializationManager.Read<int[]>(EmptyNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public int[]? ReadOneInt()
{
return SerializationManager.Read<int[]>(OneIntNode);
return SerializationManager.Read<int[]>(OneIntNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public int[]? ReadTenInts()
{
return SerializationManager.Read<int[]>(TenIntsNode);
return SerializationManager.Read<int[]>(TenIntsNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public DataDefinitionWithString[]? ReadEmptyStringDataDef()
{
return SerializationManager.Read<DataDefinitionWithString[]>(EmptyNode);
return SerializationManager.Read<DataDefinitionWithString[]>(EmptyNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public DataDefinitionWithString[]? ReadOneStringDataDef()
{
return SerializationManager.Read<DataDefinitionWithString[]>(OneStringDefNode);
return SerializationManager.Read<DataDefinitionWithString[]>(OneStringDefNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public DataDefinitionWithString[]? ReadTenStringDataDefs()
{
return SerializationManager.Read<DataDefinitionWithString[]>(TenStringDefsNode);
return SerializationManager.Read<DataDefinitionWithString[]>(TenStringDefsNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public SealedDataDefinitionWithString[]? ReadEmptySealedStringDataDef()
{
return SerializationManager.Read<SealedDataDefinitionWithString[]>(EmptyNode);
return SerializationManager.Read<SealedDataDefinitionWithString[]>(EmptyNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public SealedDataDefinitionWithString[]? ReadOneSealedStringDataDef()
{
return SerializationManager.Read<SealedDataDefinitionWithString[]>(OneStringDefNode);
return SerializationManager.Read<SealedDataDefinitionWithString[]>(OneStringDefNode, notNullableOverride: true);
}
[Benchmark]
[BenchmarkCategory("read")]
public SealedDataDefinitionWithString[]? ReadTenSealedStringDataDefs()
{
return SerializationManager.Read<SealedDataDefinitionWithString[]>(TenStringDefsNode);
return SerializationManager.Read<SealedDataDefinitionWithString[]>(TenStringDefsNode, notNullableOverride: true);
}
}
}

View File

@@ -27,7 +27,7 @@ namespace Robust.Benchmarks.Serialization.Write
var seedMapping = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>().Cast<MappingDataNode>(0);
Seed = SerializationManager.Read<SeedDataDefinition>(seedMapping);
Seed = SerializationManager.Read<SeedDataDefinition>(seedMapping, notNullableOverride: true);
}
private const string String = "ABC";
@@ -45,7 +45,7 @@ namespace Robust.Benchmarks.Serialization.Write
[Benchmark]
public DataNode WriteString()
{
return SerializationManager.WriteValue(String);
return SerializationManager.WriteValue(String, notNullableOverride: true);
}
[Benchmark]
@@ -57,13 +57,13 @@ namespace Robust.Benchmarks.Serialization.Write
[Benchmark]
public DataNode WriteDataDefinitionWithString()
{
return SerializationManager.WriteValue(DataDefinitionWithString);
return SerializationManager.WriteValue(DataDefinitionWithString, notNullableOverride: true);
}
[Benchmark]
public DataNode WriteSeedDataDefinition()
{
return SerializationManager.WriteValue(Seed);
return SerializationManager.WriteValue(Seed, notNullableOverride: true);
}
[Benchmark]

View File

@@ -151,8 +151,8 @@ namespace Robust.Client.Input
.ToArray();
mapping.Add("version", new ValueDataNode("1"));
mapping.Add("binds", _serialization.WriteValue(modifiedBindings));
mapping.Add("leaveEmpty", _serialization.WriteValue(leaveEmpty));
mapping.Add("binds", _serialization.WriteValue(modifiedBindings, notNullableOverride: true));
mapping.Add("leaveEmpty", _serialization.WriteValue(leaveEmpty, notNullableOverride: true));
var path = new ResourcePath(KeybindsPath);
using var writer = _resourceMan.UserData.OpenWriteText(path);
@@ -493,7 +493,7 @@ namespace Robust.Client.Input
if (mapping.TryGet("binds", out var BaseKeyRegsNode))
{
var baseKeyRegs = _serialization.Read<KeyBindingRegistration[]>(BaseKeyRegsNode);
var baseKeyRegs = _serialization.Read<KeyBindingRegistration[]>(BaseKeyRegsNode, notNullableOverride: true);
foreach (var reg in baseKeyRegs)
{
@@ -522,7 +522,7 @@ namespace Robust.Client.Input
if (userData && mapping.TryGet("leaveEmpty", out var node))
{
var leaveEmpty = _serialization.Read<BoundKeyFunction[]>(node);
var leaveEmpty = _serialization.Read<BoundKeyFunction[]>(node, notNullableOverride: true);
if (leaveEmpty.Length > 0)
{

View File

@@ -664,7 +664,7 @@ public sealed class MapLoaderSystem : EntitySystem
foreach (var chunkNode in yamlGridChunks.Cast<MappingDataNode>())
{
var (chunkOffsetX, chunkOffsetY) = _serManager.Read<Vector2i>(chunkNode["ind"]);
_serManager.Read(chunkNode, _context, instanceProvider: () => grid.GetOrAddChunk(chunkOffsetX, chunkOffsetY));
_serManager.Read(chunkNode, _context, instanceProvider: () => grid.GetOrAddChunk(chunkOffsetX, chunkOffsetY), notNullableOverride: true);
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
#if NETSTANDARD2_0
namespace Robust.Shared.Analyzers.Implementation;
#else
namespace Robust.Shared.Analyzers;
#endif
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.GenericParameter)]
public sealed class NotNullableFlagAttribute : Attribute
{
public readonly string TypeParameterName;
public NotNullableFlagAttribute(string typeParameterName)
{
TypeParameterName = typeParameterName;
}
}

View File

@@ -38,7 +38,7 @@ public sealed class FixtureSerializer : ITypeSerializer<List<Fixture>, SequenceD
foreach (var subNode in node)
{
var fixture = serializationManager.Read<Fixture>(subNode, hookCtx, context);
var fixture = serializationManager.Read<Fixture>(subNode, hookCtx, context, notNullableOverride: true);
value.Add(fixture);
}
@@ -64,7 +64,7 @@ public sealed class FixtureSerializer : ITypeSerializer<List<Fixture>, SequenceD
foreach (var fixture in value)
{
seq.Add(serializationManager.WriteValue(fixture, alwaysWrite, context));
seq.Add(serializationManager.WriteValue(fixture, alwaysWrite, context, notNullableOverride: true));
}
return seq;

View File

@@ -244,7 +244,7 @@ namespace Robust.Shared.Prototypes
component = newComponent;
}
serManager.CopyTo(data, ref component, context);
serManager.CopyTo(data, ref component, context, notNullableOverride: true);
}
public override string ToString()

View File

@@ -224,7 +224,7 @@ public partial class PrototypeManager
{
if (dataNode.TryGet(ParentDataFieldAttribute.Name, out var parentNode))
{
parents = _serializationManager.Read<string[]>(parentNode);
parents = _serializationManager.Read<string[]>(parentNode, notNullableOverride: true);
}
}

View File

@@ -105,13 +105,13 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type of object to create and populate.</typeparam>
/// <returns>The deserialized object, or null.</returns>
T Read<T>(DataNode node, ISerializationContext? context = null, bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, bool notNullableOverride = false);
T Read<T>(DataNode node, ISerializationContext? context = null, bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
T Read<T>(
DataNode node,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
InstantiationDelegate<T>? instanceProvider = null,
bool notNullableOverride = false);
[NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
@@ -127,7 +127,7 @@ namespace Robust.Shared.Serialization.Manager
/// <typeparam name="TNode">The node type that will be returned by the <see cref="ITypeReader{TType,TNode}"/></typeparam>
/// <returns>The deserialized object, or null.</returns>
T Read<T, TNode>(ITypeReader<T, TNode> reader, TNode node, ISerializationContext? context = null,
bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, bool notNullableOverride = false) where TNode : DataNode;
bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, [NotNullableFlag(nameof(T))] bool notNullableOverride = false) where TNode : DataNode;
T Read<T, TNode>(
ITypeReader<T, TNode> reader,
@@ -151,7 +151,7 @@ namespace Robust.Shared.Serialization.Manager
/// <typeparam name="TReader">The type of the <see cref="ITypeReader{TType,TNode}"/>.</typeparam>
/// <returns>The deserialized object, or null.</returns>
T Read<T, TNode, TReader>(TNode node, ISerializationContext? context = null,
bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, bool notNullableOverride = false) where TNode : DataNode where TReader : ITypeReader<T, TNode>;
bool skipHook = false, InstantiationDelegate<T>? instanceProvider = null, [NotNullableFlag(nameof(T))] bool notNullableOverride = false) where TNode : DataNode where TReader : ITypeReader<T, TNode>;
T Read<T, TNode, TReader>(
TNode node,
@@ -178,7 +178,7 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type to serialize.</typeparam>
/// <returns>A <see cref="DataNode"/> created from the given <see cref="value"/>.</returns>
DataNode WriteValue<T>(T value, bool alwaysWrite = false, ISerializationContext? context = null, bool notNullableOverride = false);
DataNode WriteValue<T>(T value, bool alwaysWrite = false, ISerializationContext? context = null, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
/// Serializes a value into a node using a <see cref="ITypeWriter{TType}"/> instance.
@@ -193,7 +193,7 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type to serialize.</typeparam>
/// <returns>A serialized datanode created from the given <see cref="value"/> by using the typewriter.</returns>
DataNode WriteValue<T>(ITypeWriter<T> writer, T value, bool alwaysWrite = false, ISerializationContext? context = null, bool notNullableOverride = false);
DataNode WriteValue<T>(ITypeWriter<T> writer, T value, bool alwaysWrite = false, ISerializationContext? context = null, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
/// Serializes a value into a node using a <see cref="ITypeWriter{TType}"/> type.
@@ -208,7 +208,7 @@ namespace Robust.Shared.Serialization.Manager
/// <typeparam name="T">The type to serialize.</typeparam>
/// <typeparam name="TWriter">The type of the <see cref="ITypeWriter{TType}"/>.</typeparam>
/// <returns>A serialized datanode created from the given <see cref="value"/> by using the typewriter.</returns>
DataNode WriteValue<T, TWriter>(T value, bool alwaysWrite = false, ISerializationContext? context = null, bool notNullableOverride = false) where TWriter : ITypeWriter<T>;
DataNode WriteValue<T, TWriter>(T value, bool alwaysWrite = false, ISerializationContext? context = null, [NotNullableFlag(nameof(T))] bool notNullableOverride = false) where TWriter : ITypeWriter<T>;
/// <summary>
/// Serializes a value into a node.
@@ -261,13 +261,13 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type of the objects to copy from and into.</typeparam>
void CopyTo<T>(T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
void CopyTo<T>(T source, ref T target, ISerializationContext? context = null, bool skipHook = false, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
void CopyTo<T>(
T source,
ref T? target,
ref T target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false);
[NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
/// Copies the values of one object into another using a specified <see cref="ITypeCopier{TType}"/> instance.
@@ -281,14 +281,14 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type of the objects to copy from and into.</typeparam>
void CopyTo<T>(ITypeCopier<T> copier, T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
void CopyTo<T>(ITypeCopier<T> copier, T source, ref T target, ISerializationContext? context = null, bool skipHook = false, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
void CopyTo<T>(
ITypeCopier<T> copier,
T source,
ref T? target,
ref T target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false);
[NotNullableFlag(nameof(T))] bool notNullableOverride = false);
/// <summary>
/// Copies the values of one object into another using a specified <see cref="ITypeCopier{TType}"/> type.
@@ -302,13 +302,13 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="notNullableOverride">Set true if a reference Type should not allow null. Not necessary for value types.</param>
/// <typeparam name="T">The type of the objects to copy from and into.</typeparam>
/// <typeparam name="TCopier">The type of the <see cref="ITypeCopier{TType}"/>.</typeparam>
void CopyTo<T, TCopier>(T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false) where TCopier : ITypeCopier<T>;
void CopyTo<T, TCopier>(T source, ref T target, ISerializationContext? context = null, bool skipHook = false, [NotNullableFlag(nameof(T))] bool notNullableOverride = false) where TCopier : ITypeCopier<T>;
void CopyTo<T, TCopier>(
T source,
ref T? target,
ref T target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
[NotNullableFlag(nameof(T))] bool notNullableOverride = false)
where TCopier : ITypeCopier<T>;
/// <summary>
@@ -339,7 +339,7 @@ namespace Robust.Shared.Serialization.Manager
/// <typeparam name="T">The type of the object to copy.</typeparam>
/// <returns>A copy of the given object.</returns>
[MustUseReturnValue]
T CreateCopy<T>(T source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
T CreateCopy<T>(T source, ISerializationContext? context = null, bool skipHook = false, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
[MustUseReturnValue]
T CreateCopy<T>(
@@ -359,7 +359,7 @@ namespace Robust.Shared.Serialization.Manager
/// <typeparam name="T">The type of the object to copy.</typeparam>
/// <returns>A copy of the given object.</returns>
[MustUseReturnValue]
T CreateCopy<T>(ITypeCopyCreator<T> copyCreator, T source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false);
T CreateCopy<T>(ITypeCopyCreator<T> copyCreator, T source, ISerializationContext? context = null, bool skipHook = false, [NotNullableFlag(nameof(T))] bool notNullableOverride = false);
[MustUseReturnValue]
T CreateCopy<T>(
@@ -380,7 +380,7 @@ namespace Robust.Shared.Serialization.Manager
/// <typeparam name="TCopyCreator">The type of the <see cref="ITypeCopier{TType}"/> to use.</typeparam>
/// <returns>A copy of the given object.</returns>
[MustUseReturnValue]
T CreateCopy<T, TCopyCreator>(T source, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false) where TCopyCreator : ITypeCopyCreator<T>;
T CreateCopy<T, TCopyCreator>(T source, ISerializationContext? context = null, bool skipHook = false, [NotNullableFlag(nameof(T))] bool notNullableOverride = false) where TCopyCreator : ITypeCopyCreator<T>;
[MustUseReturnValue]
T CreateCopy<T, TCopyCreator>(

View File

@@ -345,11 +345,14 @@ public sealed partial class SerializationManager
return target!;
}
private void NotNullOverrideCheck(bool notNullableOverride)
private void NotNullOverrideCheck(bool notNullableOverride, Type? type = null)
{
if (notNullableOverride) throw new NullNotAllowedException();
if (notNullableOverride || (type != null && !type.IsNullable())) throw new NullNotAllowedException();
}
private void NotNullOverrideCheck<T>(bool notNullableOverride) =>
NotNullOverrideCheck(notNullableOverride, typeof(T));
public void CopyTo(object? source, ref object? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
{
CopyTo(source, ref target, SerializationHookContext.ForSkipHooks(skipHook), context, notNullableOverride);
@@ -383,22 +386,22 @@ public sealed partial class SerializationManager
GetOrCreateCopyToBoxingDelegate(commonType)(source, ref target, hookCtx, context);
}
public void CopyTo<T>(T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
public void CopyTo<T>(T source, ref T target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
{
CopyTo<T>(source, ref target, SerializationHookContext.ForSkipHooks(skipHook), context, notNullableOverride);
}
public void CopyTo<T>(
T source,
ref T? target,
ref T target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
{
if (source == null)
{
NotNullOverrideCheck(notNullableOverride);
target = default;
NotNullOverrideCheck<T>(notNullableOverride);
target = default!;
return;
}
@@ -416,7 +419,7 @@ public sealed partial class SerializationManager
RunAfterHook(target, hookCtx);
}
public void CopyTo<T>(ITypeCopier<T> copier, T source, ref T? target, ISerializationContext? context = null,
public void CopyTo<T>(ITypeCopier<T> copier, T source, ref T target, ISerializationContext? context = null,
bool skipHook = false, bool notNullableOverride = false)
{
CopyTo<T>(
@@ -431,15 +434,15 @@ public sealed partial class SerializationManager
public void CopyTo<T>(
ITypeCopier<T> copier,
T source,
ref T? target,
ref T target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
{
if (source == null)
{
NotNullOverrideCheck(notNullableOverride);
target = default;
NotNullOverrideCheck<T>(notNullableOverride);
target = default!;
return;
}
@@ -450,7 +453,7 @@ public sealed partial class SerializationManager
RunAfterHook(target, hookCtx);
}
public void CopyTo<T, TCopier>(T source, ref T? target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
public void CopyTo<T, TCopier>(T source, ref T target, ISerializationContext? context = null, bool skipHook = false, bool notNullableOverride = false)
where TCopier : ITypeCopier<T>
{
CopyTo<T, TCopier>(
@@ -463,7 +466,7 @@ public sealed partial class SerializationManager
public void CopyTo<T, TCopier>(
T source,
ref T? target,
ref T target,
SerializationHookContext hookCtx,
ISerializationContext? context = null,
bool notNullableOverride = false)
@@ -505,7 +508,7 @@ public sealed partial class SerializationManager
{
if (source == null)
{
NotNullOverrideCheck(notNullableOverride);
NotNullOverrideCheck<T>(notNullableOverride);
return default!;
}
@@ -535,7 +538,7 @@ public sealed partial class SerializationManager
{
if (source == null)
{
NotNullOverrideCheck(notNullableOverride);
NotNullOverrideCheck<T>(notNullableOverride);
return default!;
}

View File

@@ -178,7 +178,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
foreach (var (id, component) in source)
{
target.Add(id, serializationManager.CreateCopy(component, context));
target.Add(id, serializationManager.CreateCopy(component, context, notNullableOverride: true));
}
}

View File

@@ -23,7 +23,8 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
SequenceDataNode node,
IDependencyCollection dependencies,
SerializationHookContext hookCtx,
ISerializationContext? context, ISerializationManager.InstantiationDelegate<HashSet<T>>? instanceProvider = null)
ISerializationContext? context,
ISerializationManager.InstantiationDelegate<HashSet<T>>? instanceProvider = null)
{
var set = instanceProvider != null ? instanceProvider() : new HashSet<T>();
@@ -48,7 +49,8 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
return Validate(serializationManager, node, context);
}
ValidationNode Validate(ISerializationManager serializationManager, SequenceDataNode node, ISerializationContext? context)
ValidationNode Validate(ISerializationManager serializationManager, SequenceDataNode node,
ISerializationContext? context)
{
var list = new List<ValidationNode>();
foreach (var elem in node.Sequence)
@@ -89,7 +91,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
ISerializationContext? context,
ISerializationManager.InstantiationDelegate<ImmutableHashSet<T>>? instanceProvider = null)
{
if(instanceProvider != null)
if (instanceProvider != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(ImmutableHashSet<T>)}. Ignoring...");
var set = ImmutableHashSet.CreateBuilder<T>();
@@ -101,7 +103,8 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
return set.ToImmutable();
}
public void CopyTo(ISerializationManager serializationManager, HashSet<T> source, ref HashSet<T> target, SerializationHookContext hookCtx,
public void CopyTo(ISerializationManager serializationManager, HashSet<T> source, ref HashSet<T> target,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
target.Clear();
@@ -113,7 +116,8 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
}
}
public ImmutableHashSet<T> CreateCopy(ISerializationManager serializationManager, ImmutableHashSet<T> source, SerializationHookContext hookCtx,
public ImmutableHashSet<T> CreateCopy(ISerializationManager serializationManager, ImmutableHashSet<T> source,
SerializationHookContext hookCtx,
ISerializationContext? context = null)
{
var target = new HashSet<T>();

View File

@@ -31,7 +31,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
SerializationHookContext hookCtx, ISerializationContext? context,
ISerializationManager.InstantiationDelegate<Texture>? instanceProvider = null)
{
var path = serializationManager.Read<ResourcePath>(node, hookCtx, context);
var path = serializationManager.Read<ResourcePath>(node, hookCtx, context, notNullableOverride: true);
return new Texture(path);
}
@@ -69,7 +69,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
throw new InvalidMappingException("Expected state-node as a valuenode");
}
var path = serializationManager.Read<ResourcePath>(pathNode, hookCtx, context);
var path = serializationManager.Read<ResourcePath>(pathNode, hookCtx, context, notNullableOverride: true);
return new Rsi(path, valueDataNode.Value);
}
@@ -145,7 +145,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
IDependencyCollection dependencies, bool alwaysWrite = false,
ISerializationContext? context = null)
{
return serializationManager.WriteValue(value.TexturePath, alwaysWrite, context);
return serializationManager.WriteValue(value.TexturePath, alwaysWrite, context, notNullableOverride: true);
}
public DataNode Write(ISerializationManager serializationManager, EntityPrototype value,
@@ -162,7 +162,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
ISerializationContext? context = null)
{
var mapping = new MappingDataNode();
mapping.Add("sprite", serializationManager.WriteValue(value.RsiPath));
mapping.Add("sprite", serializationManager.WriteValue(value.RsiPath, notNullableOverride: true));
mapping.Add("state", new ValueDataNode(value.RsiState));
return mapping;
}

View File

@@ -40,7 +40,7 @@ public sealed class CompositionTest : SerializationTest
};
var finalMapping = Serialization.PushComposition<CompositionTestClass, MappingDataNode>(new[] { parent1, parent2 }, child);
var val = Serialization.Read<CompositionTestClass>(finalMapping);
var val = Serialization.Read<CompositionTestClass>(finalMapping, notNullableOverride: true);
Assert.That(val.ChildValue, Is.EqualTo(1));
Assert.That(val.Parent1Value, Is.EqualTo(1));

View File

@@ -57,7 +57,7 @@ public sealed class DataRecordTest : SerializationTest
{"anotherTest", "2"}
};
var val = Serialization.Read<TwoIntRecord>(mapping);
var val = Serialization.Read<TwoIntRecord>(mapping, notNullableOverride: true);
Assert.Multiple(() =>
{
@@ -83,7 +83,7 @@ public sealed class DataRecordTest : SerializationTest
public void OneByteOneDefaultIntRecordTest()
{
var mapping = new MappingDataNode {{"a", "1"}};
var val = Serialization.Read<OneByteOneDefaultIntRecord>(mapping);
var val = Serialization.Read<OneByteOneDefaultIntRecord>(mapping, notNullableOverride: true);
Assert.Multiple(() =>
{
@@ -96,7 +96,7 @@ public sealed class DataRecordTest : SerializationTest
public void OneLongRecordTest()
{
var mapping = new MappingDataNode {{"a", "1"}};
var val = Serialization.Read<OneLongRecord>(mapping);
var val = Serialization.Read<OneLongRecord>(mapping, notNullableOverride: true);
Assert.That(val.A, Is.EqualTo(1));
}
@@ -105,7 +105,7 @@ public sealed class DataRecordTest : SerializationTest
public void OneLongMinValueRecordTest()
{
var mapping = new MappingDataNode {{"a", long.MinValue.ToString()}};
var val = Serialization.Read<OneLongRecord>(mapping);
var val = Serialization.Read<OneLongRecord>(mapping, notNullableOverride: true);
Assert.That(val.A, Is.EqualTo(long.MinValue));
}
@@ -114,7 +114,7 @@ public sealed class DataRecordTest : SerializationTest
public void OneLongMaxValueRecordTest()
{
var mapping = new MappingDataNode {{"a", long.MaxValue.ToString()}};
var val = Serialization.Read<OneLongRecord>(mapping);
var val = Serialization.Read<OneLongRecord>(mapping, notNullableOverride: true);
Assert.That(val.A, Is.EqualTo(long.MaxValue));
}
@@ -123,7 +123,7 @@ public sealed class DataRecordTest : SerializationTest
public void OneLongDefaultRecordTest()
{
var mapping = new MappingDataNode();
var val = Serialization.Read<OneLongDefaultRecord>(mapping);
var val = Serialization.Read<OneLongDefaultRecord>(mapping, notNullableOverride: true);
Assert.That(val.A, Is.EqualTo(5));
}
@@ -132,7 +132,7 @@ public sealed class DataRecordTest : SerializationTest
public void OneULongRecordMaxValueTest()
{
var mapping = new MappingDataNode {{"a", ulong.MaxValue.ToString()}};
var val = Serialization.Read<OneULongRecord>(mapping);
var val = Serialization.Read<OneULongRecord>(mapping, notNullableOverride: true);
Assert.That(val.A, Is.EqualTo(ulong.MaxValue));
}
@@ -141,7 +141,7 @@ public sealed class DataRecordTest : SerializationTest
public void PrototypeTest()
{
var mapping = new MappingDataNode {{"id", "ABC"}};
var val = Serialization.Read<PrototypeRecord>(mapping);
var val = Serialization.Read<PrototypeRecord>(mapping, notNullableOverride: true);
Assert.That(val.ID, Is.EqualTo("ABC"));
}
@@ -167,7 +167,7 @@ public sealed class DataRecordTest : SerializationTest
}
}
};
var val = Serialization.Read<IntStructHolder>(mapping);
var val = Serialization.Read<IntStructHolder>(mapping, notNullableOverride: true);
Assert.That(val.Struct.Value, Is.EqualTo(42));
}
@@ -190,7 +190,7 @@ public sealed class DataRecordTest : SerializationTest
}
}
};
var val = Serialization.Read<TwoIntStructHolder>(mapping);
var val = Serialization.Read<TwoIntStructHolder>(mapping, notNullableOverride: true);
Assert.Multiple(() =>
{

View File

@@ -36,7 +36,7 @@ public sealed class IncludeTest : RobustUnitTest
mapping.Add("f1", "1");
mapping.Add("f2", "true");
var val = serv3Mgr.Read<ReadWriteTestDataDefinition>(mapping);
var val = serv3Mgr.Read<ReadWriteTestDataDefinition>(mapping, notNullableOverride: true);
Assert.That(val.F1, Is.EqualTo(1));
Assert.That(val.Nested.F1, Is.EqualTo(1));

View File

@@ -35,7 +35,7 @@ namespace Robust.UnitTesting.Shared.Serialization
mapping.Add(GetOnlyPropertyWithOtherAttributeFieldTargetedName, new ValueDataNode("25"));
mapping.Add(GetOnlyPropertyFieldTargetedAndOtherAttributeName, new ValueDataNode("30"));
var definition = Serialization.Read<PropertyAndFieldDefinitionTestDefinition>(mapping);
var definition = Serialization.Read<PropertyAndFieldDefinitionTestDefinition>(mapping, notNullableOverride: true);
Assert.NotNull(definition);

View File

@@ -34,7 +34,7 @@ namespace Robust.UnitTesting.Shared.Serialization
var mapping = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>().Cast<MappingDataNode>(0);
var component = serializationManager.Read<PriorityTestComponent>(mapping);
var component = serializationManager.Read<PriorityTestComponent>(mapping, notNullableOverride: true);
Assert.That(component.Strings.Count, Is.EqualTo(3));
Assert.That(component.First, Is.EqualTo("A"));

View File

@@ -147,7 +147,7 @@ public sealed partial class DataDefinitionTests : SerializationTest
public void Read_NT_NV<T>(string fieldName, DataNode node, Func<T> value, Func<T> altValue)
{
var mapping = new MappingDataNode{ { fieldName, ValueDataNode.Null() } };
var res = Serialization.Read<DataDefTestDummy>(mapping);
var res = Serialization.Read<DataDefTestDummy>(mapping, notNullableOverride: true);
Assert.Null(GetValue(res, fieldName));
}
@@ -155,7 +155,7 @@ public sealed partial class DataDefinitionTests : SerializationTest
public void Read_NT_RV_AND_RT_RV<T>(string fieldName, DataNode node, Func<T> value, Func<T> altValue)
{
var mapping = new MappingDataNode{ { fieldName, node } };
var res = Serialization.Read<DataDefTestDummy>(mapping);
var res = Serialization.Read<DataDefTestDummy>(mapping, notNullableOverride: true);
Assert.That(GetValue(res, fieldName), Is.EqualTo(value()));
}
@@ -163,7 +163,7 @@ public sealed partial class DataDefinitionTests : SerializationTest
public void Read_RT_NV<T>(string fieldName, DataNode node, Func<T> value, Func<T> altValue)
{
var mapping = new MappingDataNode{ { fieldName, ValueDataNode.Null() } };
Assert.That(() => Serialization.Read<DataDefTestDummy>(mapping), Throws.InstanceOf<NullNotAllowedException>());
Assert.That(() => Serialization.Read<DataDefTestDummy>(mapping, notNullableOverride: true), Throws.InstanceOf<NullNotAllowedException>());
}
[TestCaseSource(nameof(NullableFieldsData))]
@@ -208,7 +208,7 @@ public sealed partial class DataDefinitionTests : SerializationTest
SetValue(source, fieldName, null);
var target = new DataDefTestDummy();
SetValue(target, fieldName, null);
Serialization.CopyTo(source, ref target);
Serialization.CopyTo(source, ref target, notNullableOverride: true);
Assert.NotNull(target);
Assert.Null(GetValue(target!, fieldName));
}
@@ -220,7 +220,7 @@ public sealed partial class DataDefinitionTests : SerializationTest
SetValue(source, fieldName, null);
var target = new DataDefTestDummy();
SetValue(target, fieldName, altValue());
Serialization.CopyTo(source, ref target);
Serialization.CopyTo(source, ref target, notNullableOverride: true);
Assert.NotNull(target);
Assert.Null(GetValue(target!, fieldName));
}
@@ -232,7 +232,7 @@ public sealed partial class DataDefinitionTests : SerializationTest
SetValue(source, fieldName, value());
var target = new DataDefTestDummy();
SetValue(target, fieldName, null);
Serialization.CopyTo(source, ref target);
Serialization.CopyTo(source, ref target, notNullableOverride: true);
Assert.NotNull(target);
Assert.That(GetValue(target!, fieldName), Is.EqualTo(value()));
}
@@ -244,7 +244,7 @@ public sealed partial class DataDefinitionTests : SerializationTest
SetValue(source, fieldName, value());
var target = new DataDefTestDummy();
SetValue(target, fieldName, altValue());
Serialization.CopyTo(source, ref target);
Serialization.CopyTo(source, ref target, notNullableOverride: true);
Assert.NotNull(target);
Assert.That(GetValue(target!, fieldName), Is.EqualTo(value()));
}
@@ -258,7 +258,7 @@ public sealed partial class DataDefinitionTests : SerializationTest
SetValue(source, fieldName, null);
var target = new DataDefTestDummy();
SetValue(target, fieldName, null);
Assert.That(() => Serialization.CopyTo(source, ref target), Throws.InstanceOf<NullNotAllowedException>());
Assert.That(() => Serialization.CopyTo(source, ref target, notNullableOverride: true), Throws.InstanceOf<NullNotAllowedException>());
}
[TestCaseSource(nameof(RegularFieldsData))]
@@ -270,7 +270,7 @@ public sealed partial class DataDefinitionTests : SerializationTest
SetValue(source, fieldName, null);
var target = new DataDefTestDummy();
SetValue(target, fieldName, altValue());
Assert.That(() => Serialization.CopyTo(source, ref target), Throws.InstanceOf<NullNotAllowedException>());
Assert.That(() => Serialization.CopyTo(source, ref target, notNullableOverride: true), Throws.InstanceOf<NullNotAllowedException>());
}
[TestCaseSource(nameof(RegularFieldsData))]

View File

@@ -445,8 +445,8 @@ public sealed partial class ManagerTests : SerializationTest
public void CopyTo_RT_NS_NT_Class<T>(DataNode _, Func<T> __, Func<T> ___, bool useContext, object[] ____)
where T : class
{
T? target = null;
Assert.That(() => { Serialization.CopyTo<T>(null!, ref target, context: Context(useContext), notNullableOverride: true); },
T target = null!;
Assert.That(() => { Serialization.CopyTo(null!, ref target, context: Context(useContext), notNullableOverride: true); },
Throws.TypeOf<NullNotAllowedException>());
}
@@ -464,8 +464,8 @@ public sealed partial class ManagerTests : SerializationTest
public void CopyTo_RT_RS_NT_Class<T>(DataNode _, Func<T> value, Func<T> ___, bool useContext,
object[] valueExtractors) where T : class
{
T? target = null;
Serialization.CopyTo<T>(value(), ref target, context: Context(useContext));
T target = null!;
Serialization.CopyTo(value(), ref target, context: Context(useContext));
Assert.NotNull(target);
AssertEqual(target!, value(), valueExtractors);
}
@@ -533,9 +533,9 @@ public sealed partial class ManagerTests : SerializationTest
[Test]
public void CopyTo_CopyByRef_Class()
{
CopyByRefTestClass? target = null;
CopyByRefTestClass target = null!;
var source = new CopyByRefTestClass();
Serialization.CopyTo(source, ref target);
Serialization.CopyTo(source, ref target, notNullableOverride: true);
Assert.NotNull(target);
Assert.That(target!, Is.SameAs(source));
}
@@ -552,7 +552,7 @@ public sealed partial class ManagerTests : SerializationTest
public void CreateCopy_CopyByRef_Class()
{
var source = new CopyByRefTestClass();
var copy = Serialization.CreateCopy(source);
var copy = Serialization.CreateCopy(source, notNullableOverride: true);
Assert.That(copy, Is.SameAs(source));
}

View File

@@ -47,7 +47,7 @@ public sealed class ReadValueProviderTests : SerializationTest
{
var data = "someData";
var instance = new SelfSerializeValueProviderTestDummy();
var result = Serialization.Read(new ValueDataNode(data), instanceProvider: () => instance);
var result = Serialization.Read(new ValueDataNode(data), instanceProvider: () => instance, notNullableOverride: true);
Assert.That(result, Is.SameAs(instance));
Assert.That(result.Data, Is.EqualTo(instance.Data));
}
@@ -57,7 +57,7 @@ public sealed class ReadValueProviderTests : SerializationTest
{
var data = "someData";
var instance = new SelfSerializeValueProviderTestDummy();
var result = Serialization.Read<IBaseInterface>(new ValueDataNode(data){Tag = $"!type:{nameof(SelfSerializeValueProviderTestDummy)}"}, instanceProvider: () => instance);
var result = Serialization.Read<IBaseInterface>(new ValueDataNode(data){Tag = $"!type:{nameof(SelfSerializeValueProviderTestDummy)}"}, instanceProvider: () => instance, notNullableOverride: true);
Assert.That(result, Is.SameAs(instance));
Assert.That(((SelfSerializeValueProviderTestDummy)result).Data, Is.EqualTo(instance.Data));
}
@@ -68,7 +68,7 @@ public sealed class ReadValueProviderTests : SerializationTest
var data = "someData";
var mapping = new MappingDataNode { { "data", data } };
var instance = new DataDefinitionValueProviderTestDummy();
var result = Serialization.Read(mapping, instanceProvider: () => instance);
var result = Serialization.Read(mapping, instanceProvider: () => instance, notNullableOverride: true);
Assert.That(result, Is.SameAs(instance));
Assert.That(result.Data, Is.EqualTo(instance.Data));
}
@@ -82,7 +82,7 @@ public sealed class ReadValueProviderTests : SerializationTest
Tag = $"!type:{nameof(DataDefinitionValueProviderTestDummy)}"
};
var instance = new DataDefinitionValueProviderTestDummy();
var result = Serialization.Read<IBaseInterface>(mapping, instanceProvider: () => instance);
var result = Serialization.Read<IBaseInterface>(mapping, instanceProvider: () => instance, notNullableOverride: true);
Assert.That(result, Is.SameAs(instance));
Assert.That(((DataDefinitionValueProviderTestDummy)result).Data, Is.EqualTo(instance.Data));
}
@@ -91,7 +91,7 @@ public sealed class ReadValueProviderTests : SerializationTest
public void DataDefinitionValueBaseTest()
{
var instance = new DataDefinitionValueProviderTestDummy();
var result = Serialization.Read<IBaseInterface>(new ValueDataNode{Tag = $"!type:{nameof(DataDefinitionValueProviderTestDummy)}"}, instanceProvider: () => instance);
var result = Serialization.Read<IBaseInterface>(new ValueDataNode{Tag = $"!type:{nameof(DataDefinitionValueProviderTestDummy)}"}, instanceProvider: () => instance, notNullableOverride: true);
Assert.That(result, Is.SameAs(instance));
}
@@ -99,6 +99,6 @@ public sealed class ReadValueProviderTests : SerializationTest
public void DataDefinitionValueBaseInvalidTest()
{
var instance = new OtherDataDefinitionValueProviderTestDummy();
Assert.That(() => Serialization.Read<IBaseInterface>(new ValueDataNode{Tag = $"!type:{nameof(DataDefinitionValueProviderTestDummy)}"}, instanceProvider: () => instance),Throws.InstanceOf<InvalidInstanceReturnedException>());
Assert.That(() => Serialization.Read<IBaseInterface>(new ValueDataNode{Tag = $"!type:{nameof(DataDefinitionValueProviderTestDummy)}"}, instanceProvider: () => instance, notNullableOverride: true),Throws.InstanceOf<InvalidInstanceReturnedException>());
}
}

View File

@@ -27,7 +27,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers
{
var list = new[] {"A", "E"};
var node = new SequenceDataNode("A", "E");
var deserializedList = Serialization.Read<string[]>(node);
var deserializedList = Serialization.Read<string[]>(node, notNullableOverride: true);
Assert.That(deserializedList, Is.EqualTo(list));
}

View File

@@ -48,7 +48,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers
var mapping = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>();
var deserializedRegistry = Serialization.Read<ComponentRegistry>(mapping);
var deserializedRegistry = Serialization.Read<ComponentRegistry>(mapping, notNullableOverride: true);
Assert.That(deserializedRegistry.Count, Is.EqualTo(1));
Assert.That(deserializedRegistry.ContainsKey("Test"));

View File

@@ -28,7 +28,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers.Custom
Assert.That(sequence.Sequence.Count, Is.EqualTo(1));
Assert.That(sequence.Cast<ValueDataNode>(0).Value, Is.EqualTo("One"));
var value = Serialization.Read<TestDefinition>(node);
var value = Serialization.Read<TestDefinition>(node, notNullableOverride: true);
Assert.That(value.Flag, Is.EqualTo(1));
}
@@ -45,7 +45,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers.Custom
Assert.That(sequence.Sequence, Does.Contain(new ValueDataNode("One")));
Assert.That(sequence.Sequence, Does.Contain(new ValueDataNode("Two")));
var value = Serialization.Read<TestDefinition>(node);
var value = Serialization.Read<TestDefinition>(node, notNullableOverride: true);
Assert.That(value.Flag, Is.EqualTo(3));
}
@@ -61,7 +61,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers.Custom
Assert.That(sequence.Sequence.Count, Is.EqualTo(1));
Assert.That(sequence.Cast<ValueDataNode>(0).Value, Is.EqualTo("NegativeFlag"));
var value = Serialization.Read<TestDefinition>(node);
var value = Serialization.Read<TestDefinition>(node, notNullableOverride: true);
Assert.That(value.Flag, Is.EqualTo(TestFlags.Negative));
}

View File

@@ -88,7 +88,7 @@ entitiesImmutableList:
stream.Load(new StringReader(DataString));
var node = stream.Documents[0].RootNode.ToDataNode();
var definition = Serialization.Read<PrototypeIdListSerializerTestDataDefinition>(node);
var definition = Serialization.Read<PrototypeIdListSerializerTestDataDefinition>(node, notNullableOverride: true);
Assert.NotNull(definition);

View File

@@ -44,7 +44,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers
node.Add("2", new ValueDataNode("B"));
node.Add("3", new ValueDataNode("C"));
var deserializedDictionary = Serialization.Read<Dictionary<int, string>>(node);
var deserializedDictionary = Serialization.Read<Dictionary<int, string>>(node, notNullableOverride: true);
Assert.That(deserializedDictionary, Is.EqualTo(dictionary));
}

View File

@@ -28,7 +28,7 @@ public sealed class FormattedMessageSerializerTest : SerializationTest
public void DeserializationTest(string text)
{
var node = new ValueDataNode(text);
var deserializedMessage = Serialization.Read<FormattedMessage>(node);
var deserializedMessage = Serialization.Read<FormattedMessage>(node, notNullableOverride: true);
Assert.That(deserializedMessage.ToMarkup(), Is.EqualTo(text));
}
}

View File

@@ -28,7 +28,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers
{
var list = new HashSet<string> {"A", "E"};
var node = new SequenceDataNode("A", "E");
var deserializedList = Serialization.Read<HashSet<string>>(node);
var deserializedList = Serialization.Read<HashSet<string>>(node, notNullableOverride: true);
Assert.That(deserializedList, Is.EqualTo(list));
}

View File

@@ -28,7 +28,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers
{
var list = new List<string> {"A", "E"};
var node = new SequenceDataNode("A", "E");
var deserializedList = Serialization.Read<List<string>>(node);
var deserializedList = Serialization.Read<List<string>>(node, notNullableOverride: true);
Assert.That(deserializedList, Is.EqualTo(list));
}
@@ -38,7 +38,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers
{
var node = new SequenceDataNode("A", "E");
var result = Serialization.Read<List<string>, SequenceDataNode, ListSerializers<string>>(node);
var result = Serialization.Read<List<string>, SequenceDataNode, ListSerializers<string>>(node, notNullableOverride: true);
var list = (List<string>?) result;
Assert.NotNull(list);
@@ -53,7 +53,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers
{
var list = new List<string> {"A", "E"};
var node = (SequenceDataNode) Serialization.WriteValue<List<string>, ListSerializers<string>>(list);
var node = (SequenceDataNode) Serialization.WriteValue<List<string>, ListSerializers<string>>(list, notNullableOverride: true);
Assert.That(node.Sequence.Count, Is.EqualTo(2));
Assert.That(node.Cast<ValueDataNode>(0).Value, Is.EqualTo("A"));
@@ -69,7 +69,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers
Assert.IsNotEmpty(source);
Assert.IsEmpty(target);
Serialization.CopyTo<List<string>, ListSerializers<string>>(source, ref target);
Serialization.CopyTo<List<string>, ListSerializers<string>>(source, ref target, notNullableOverride: true);
Assert.NotNull(source);

View File

@@ -27,7 +27,7 @@ namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers
{
var str = "[AEIOU]";
var node = new ValueDataNode(str);
var deserializedRegex = Serialization.Read<Regex>(node);
var deserializedRegex = Serialization.Read<Regex>(node, notNullableOverride: true);
var regex = new Regex(str, RegexOptions.Compiled);
Assert.That(deserializedRegex.ToString(), Is.EqualTo(regex.ToString()));

View File

@@ -28,7 +28,7 @@ namespace Robust.UnitTesting.Shared.Serialization.YamlObjectSerializerTests
// Arrange
var data = _serializableList;
var serMan = IoCManager.Resolve<ISerializationManager>();
var sequence = (SequenceDataNode) serMan.WriteValue(data);
var sequence = (SequenceDataNode) serMan.WriteValue(data, notNullableOverride: true);
var mapping = new MappingDataNode();
mapping.Add("datalist", sequence);
@@ -45,7 +45,7 @@ namespace Robust.UnitTesting.Shared.Serialization.YamlObjectSerializerTests
var rootNode = YamlTextToNode(_serializedListYaml);
// Act
var data = serMan.Read<ImmutableList<int>>(new SequenceDataNode((YamlSequenceNode)rootNode.Children[0].Value));
var data = serMan.Read<ImmutableList<int>>(new SequenceDataNode((YamlSequenceNode)rootNode.Children[0].Value), notNullableOverride: true);
// Assert
Assert.That(data, Is.Not.Null);

View File

@@ -32,7 +32,7 @@ namespace Robust.UnitTesting.Shared.Serialization.YamlObjectSerializerTests
TestPropertyTwo = 10
};
var serMan = IoCManager.Resolve<ISerializationManager>();
var mapping = (MappingDataNode) serMan.WriteValue(type);
var mapping = (MappingDataNode) serMan.WriteValue(type, notNullableOverride: true);
Assert.IsNotEmpty(mapping.Children);
@@ -69,7 +69,7 @@ namespace Robust.UnitTesting.Shared.Serialization.YamlObjectSerializerTests
var mapping = (YamlMappingNode) yamlStream.Documents[0].RootNode[0];
var serMan = IoCManager.Resolve<ISerializationManager>();
var type = serMan.Read<ITestType>(mapping["test"].ToDataNode());
var type = serMan.Read<ITestType>(mapping["test"].ToDataNode(), notNullableOverride: true);
Assert.NotNull(type);
Assert.IsInstanceOf<TestTypeTwo>(type);

View File

@@ -25,7 +25,7 @@ namespace Robust.UnitTesting.Shared.Serialization.YamlObjectSerializerTests
{
ITestType type = new TestTypeOne();
var serMan = IoCManager.Resolve<ISerializationManager>();
var mapping = serMan.WriteValue(type);
var mapping = serMan.WriteValue(type, notNullableOverride: true);
Assert.IsInstanceOf<MappingDataNode>(mapping);
@@ -56,7 +56,7 @@ test:
var mapping = (YamlMappingNode) yamlStream.Documents[0].RootNode;
var serMan = IoCManager.Resolve<ISerializationManager>();
var type = serMan.Read<ITestType>(new MappingDataNode(mapping)["test"]);
var type = serMan.Read<ITestType>(new MappingDataNode(mapping)["test"], notNullableOverride: true);
Assert.NotNull(type);
Assert.IsInstanceOf<TestTypeOne>(type);