Add MeansDataDefinition support to DataDefinitionAnalyzer (#5699)

* Add MeansDataDefinition support to DataDefinitionAnalyzer

* Poke tests

* Fix violations in engine

* Fix more lacking partials

* Fix tests

---------

Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
This commit is contained in:
Tayrtahn
2025-12-17 13:47:30 -05:00
committed by GitHub
parent d7abbad717
commit dd86bf980d
8 changed files with 36 additions and 21 deletions

View File

@@ -16,6 +16,7 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
{
private const string DataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataDefinitionAttribute";
private const string ImplicitDataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.ImplicitDataDefinitionForInheritorsAttribute";
private const string MeansDataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.MeansDataDefinitionAttribute";
private const string DataFieldBaseNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataFieldBaseAttribute";
private const string ViewVariablesNamespace = "Robust.Shared.ViewVariables.ViewVariablesAttribute";
private const string NotYamlSerializableName = "Robust.Shared.Serialization.Manager.Attributes.NotYamlSerializableAttribute";
@@ -270,6 +271,7 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
return false;
return HasAttribute(type, DataDefinitionNamespace) ||
MeansDataDefinition(type) ||
IsImplicitDataDefinition(type);
}
@@ -425,6 +427,19 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
return (VVAccess)accessByte == VVAccess.ReadWrite;
}
private static bool MeansDataDefinition(ITypeSymbol type)
{
foreach (var attribute in type.GetAttributes())
{
if (attribute.AttributeClass is null)
continue;
if (HasAttribute(attribute.AttributeClass, MeansDataDefinitionNamespace))
return true;
}
return false;
}
private static bool IsNotYamlSerializable(ISymbol field, ITypeSymbol type)
{
return HasAttribute(type, NotYamlSerializableName);

View File

@@ -34,7 +34,7 @@ public sealed partial class UITheme : IPrototype
private ResPath _path;
[DataField("colors", readOnly: true)] // This is a prototype, why is this readonly??
public FrozenDictionary<string, Color>? Colors { get; }
public FrozenDictionary<string, Color>? Colors;
public ResPath Path => _path == default ? new ResPath(DefaultPath+"/"+ID) : _path;
private void ValidateFilePath(IResourceManager manager)

View File

@@ -15,7 +15,7 @@ namespace Robust.UnitTesting.Shared.Prototypes
{
[UsedImplicitly]
[TestFixture]
internal sealed class PrototypeManager_Test : OurRobustUnitTest
internal sealed partial class PrototypeManager_Test : OurRobustUnitTest
{
private const string FakeWrenchProtoId = "wrench";
private const string YamlTesterProtoId = "yamltester";
@@ -151,7 +151,7 @@ namespace Robust.UnitTesting.Shared.Prototypes
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<CircleTestPrototype>))]
public string[]? Parents { get; private set; }
[AbstractDataField]
public bool Abstract { get; }
public bool Abstract { get; private set; }
}
public enum YamlTestEnum : byte

View File

@@ -12,25 +12,25 @@ namespace Robust.UnitTesting.Shared.Serialization;
public sealed partial class DataRecordTest : OurSerializationTest
{
[DataRecord]
public record TwoIntRecord(int aTest, int AnotherTest);
public partial record TwoIntRecord(int aTest, int AnotherTest);
[DataRecord]
public record OneByteOneDefaultIntRecord(byte A, int B = 5);
public partial record OneByteOneDefaultIntRecord(byte A, int B = 5);
[DataRecord]
public record OneLongRecord(long A);
public partial record OneLongRecord(long A);
[DataRecord]
public record OneLongDefaultRecord(long A = 5);
public partial record OneLongDefaultRecord(long A = 5);
[DataRecord]
public record OneULongRecord(ulong A);
public partial record OneULongRecord(ulong A);
[PrototypeRecord("emptyTestPrototypeRecord")]
public record PrototypeRecord([field: IdDataField] string ID) : IPrototype;
public partial record PrototypeRecord([field: IdDataField] string ID) : IPrototype;
[DataRecord]
public record IntStructHolder(IntStruct Struct);
public partial record IntStructHolder(IntStruct Struct);
[DataDefinition]
public partial struct IntStruct
@@ -44,13 +44,13 @@ public sealed partial class DataRecordTest : OurSerializationTest
}
[DataRecord]
public record TwoIntStructHolder(IntStruct Struct1, IntStruct Struct2);
public partial record TwoIntStructHolder(IntStruct Struct1, IntStruct Struct2);
[DataRecord]
public record struct DataRecordStruct(IntStruct Struct, string String, int Integer);
public partial record struct DataRecordStruct(IntStruct Struct, string String, int Integer);
[DataRecord]
public record struct DataRecordWithProperties
public partial record struct DataRecordWithProperties
{
public Vector2 Position;
public int Foo { get; }
@@ -59,7 +59,7 @@ public sealed partial class DataRecordTest : OurSerializationTest
}
[DataRecord]
public readonly record struct ReadonlyDataRecord
public readonly partial record struct ReadonlyDataRecord
{
public readonly Vector2 Position;
public int Foo { get; }

View File

@@ -13,7 +13,7 @@ namespace Robust.Shared.Audio;
public sealed partial class AudioPresetPrototype : IPrototype
{
[IdDataField]
public string ID { get; } = default!;
public string ID { get; private set; } = default!;
/// <summary>
/// Should the engine automatically create an auxiliary audio effect slot for this.

View File

@@ -14,7 +14,7 @@ namespace Robust.Shared.Map
/// A set of coordinates relative to another entity.
/// </summary>
[PublicAPI, DataRecord]
public readonly record struct EntityCoordinates : ISpanFormattable
public readonly partial record struct EntityCoordinates : ISpanFormattable
{
public static readonly EntityCoordinates Invalid = new(EntityUid.Invalid, Vector2.Zero);

View File

@@ -13,7 +13,7 @@ namespace Robust.Shared.Map
/// </summary>
[PublicAPI, DataRecord]
[Serializable, NetSerializable]
public readonly record struct MapCoordinates : ISpanFormattable
public readonly partial record struct MapCoordinates : ISpanFormattable
{
public static readonly MapCoordinates Nullspace = new(Vector2.Zero, MapId.Nullspace);

View File

@@ -141,19 +141,19 @@ namespace Robust.Shared.Prototypes
/// </summary>
[ViewVariables]
[ParentDataFieldAttribute(typeof(AbstractPrototypeIdArraySerializer<EntityPrototype>))]
public string[]? Parents { get; }
public string[]? Parents { get; private set; }
[ViewVariables]
[NeverPushInheritance]
[AbstractDataField]
public bool Abstract { get; }
public bool Abstract { get; private set; }
/// <summary>
/// A dictionary mapping the component type list to the YAML mapping containing their settings.
/// </summary>
[DataField("components")]
[AlwaysPushInheritance]
public ComponentRegistry Components { get; } = new();
public ComponentRegistry Components = new();
public EntityPrototype()
{
@@ -286,7 +286,7 @@ namespace Robust.Shared.Prototypes
}
[DataRecord]
public record ComponentRegistryEntry(IComponent Component, MappingDataNode Mapping);
public partial record ComponentRegistryEntry(IComponent Component, MappingDataNode Mapping);
[DataDefinition]
public sealed partial class EntityPlacementProperties