diff --git a/Obsidian.SourceGenerators/AnalyzerReleases.Shipped.md b/Obsidian.SourceGenerators/AnalyzerReleases.Shipped.md new file mode 100644 index 000000000..60b59dd99 --- /dev/null +++ b/Obsidian.SourceGenerators/AnalyzerReleases.Shipped.md @@ -0,0 +1,3 @@ +; Shipped analyzer releases +; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + diff --git a/Obsidian.SourceGenerators/AnalyzerReleases.Unshipped.md b/Obsidian.SourceGenerators/AnalyzerReleases.Unshipped.md new file mode 100644 index 000000000..22077ed2a --- /dev/null +++ b/Obsidian.SourceGenerators/AnalyzerReleases.Unshipped.md @@ -0,0 +1,10 @@ +; Unshipped analyzer release +; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + +### New rules + +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +DBG001 | SerializationMethodGeneration | Warning | DiagnosticDescriptors +DBG002 | SerializationMethodGeneration | Warning | DiagnosticDescriptors +DBG003 | SerializationMethodGeneration | Warning | DiagnosticDescriptors diff --git a/Obsidian.SourceGenerators/Extensions.CodeBuilder.cs b/Obsidian.SourceGenerators/Extensions.CodeBuilder.cs index 1d2c7b367..ae9dbcee7 100644 --- a/Obsidian.SourceGenerators/Extensions.CodeBuilder.cs +++ b/Obsidian.SourceGenerators/Extensions.CodeBuilder.cs @@ -1,5 +1,6 @@ using Obsidian.SourceGenerators.Registry; using Obsidian.SourceGenerators.Registry.Models; +using System.Globalization; using System.Text.Json; namespace Obsidian.SourceGenerators; @@ -102,9 +103,9 @@ internal static void AppendValueType(this CodeBuilder builder, JsonElement eleme else if (element.TryGetInt64(out var longValue)) builder.Append($"{longValue} }},"); else if (element.TryGetSingle(out var floatValue)) - builder.Append($"{floatValue}f }},"); + builder.Append($"{floatValue.ToString(CultureInfo.InvariantCulture)}f }},"); else if (element.TryGetDouble(out var doubleValue)) - builder.Append($"{doubleValue}d }},"); + builder.Append($"{doubleValue.ToString(CultureInfo.InvariantCulture)}d }},"); break; } case JsonValueKind.True: @@ -133,9 +134,9 @@ internal static void AppendValueType(this CodeBuilder builder, JsonElement eleme else if (element.TryGetInt64(out var longValue)) builder.Append($"{longValue}, "); else if (element.TryGetSingle(out var floatValue)) - builder.Append($"{floatValue}f, "); + builder.Append($"{floatValue.ToString(CultureInfo.InvariantCulture)}f, "); else if (element.TryGetDouble(out var doubleValue)) - builder.Append($"{doubleValue}d, "); + builder.Append($"{doubleValue.ToString(CultureInfo.InvariantCulture)}d, "); break; } case JsonValueKind.True: diff --git a/Obsidian.SourceGenerators/Extensions.cs b/Obsidian.SourceGenerators/Extensions.cs index 635c467ea..de35e8a11 100644 --- a/Obsidian.SourceGenerators/Extensions.cs +++ b/Obsidian.SourceGenerators/Extensions.cs @@ -15,4 +15,10 @@ internal static string CompileName(this Tag tag, bool last = false) return tag.Parent == tag.Type ? tag.Name : $"{tag.Type.ToPascalCase()}.{tag.Name}"; } + + public static void Deconstruct(this IGrouping grouping, out TKey key, out List values) + { + key = grouping.Key; + values = grouping.ToList(); + } } diff --git a/Obsidian.SourceGenerators/Obsidian.SourceGenerators.csproj b/Obsidian.SourceGenerators/Obsidian.SourceGenerators.csproj index ea5fb8952..8e5dfde81 100644 --- a/Obsidian.SourceGenerators/Obsidian.SourceGenerators.csproj +++ b/Obsidian.SourceGenerators/Obsidian.SourceGenerators.csproj @@ -7,6 +7,7 @@ true Generated true + true diff --git a/Obsidian.SourceGenerators/Packets/AttributeOwner.cs b/Obsidian.SourceGenerators/Packets/AttributeOwner.cs index e5c6411b8..ccab85fa3 100644 --- a/Obsidian.SourceGenerators/Packets/AttributeOwner.cs +++ b/Obsidian.SourceGenerators/Packets/AttributeOwner.cs @@ -2,12 +2,12 @@ namespace Obsidian.SourceGenerators.Packets; -internal abstract class AttributeOwner +internal abstract class AttributeOwner(AttributeFlags flags, AttributeBehaviorBase[] attributes) { - public AttributeFlags Flags { get; set; } - public AttributeBehaviorBase[] Attributes { get; set; } + public AttributeFlags Flags { get; } = flags; + public AttributeBehaviorBase[] Attributes { get; } = attributes; - public bool TryGetAttribute(out TAttribute attribute) where TAttribute : AttributeBehaviorBase + public bool TryGetAttribute(out TAttribute? attribute) where TAttribute : AttributeBehaviorBase { for (int i = 0; i < Attributes.Length; i++) { @@ -21,4 +21,20 @@ public bool TryGetAttribute(out TAttribute attribute) where TAttribu attribute = default; return false; } + + protected static AttributeFlags AggregateFlags(AttributeBehaviorBase[] attributes) + { + var flags = AttributeFlags.None; + foreach (AttributeBehaviorBase attribute in attributes) + { + flags |= attribute.Flag; + } + return flags; + } + + protected static string GetRelativeTypeName(string typeName) + { + int dotIndex = typeName.LastIndexOf('.'); + return dotIndex >= 0 ? typeName.Substring(dotIndex + 1) : typeName; + } } diff --git a/Obsidian.SourceGenerators/Packets/Attributes/AttributeBehaviorBase.cs b/Obsidian.SourceGenerators/Packets/Attributes/AttributeBehaviorBase.cs index d9295c248..c5d3652a7 100644 --- a/Obsidian.SourceGenerators/Packets/Attributes/AttributeBehaviorBase.cs +++ b/Obsidian.SourceGenerators/Packets/Attributes/AttributeBehaviorBase.cs @@ -3,19 +3,13 @@ namespace Obsidian.SourceGenerators.Packets.Attributes; -internal abstract class AttributeBehaviorBase +internal abstract class AttributeBehaviorBase(AttributeSyntax attributeSyntax) { public abstract string Name { get; } public abstract AttributeFlags Flag { get; } - protected readonly AttributeSyntax syntax; - private readonly AttributeArgumentSyntax[] arguments; - - public AttributeBehaviorBase(AttributeSyntax attributeSyntax) - { - syntax = attributeSyntax; - arguments = attributeSyntax?.ArgumentList?.Arguments.Select(arg => arg).ToArray() ?? []; - } + protected readonly AttributeSyntax syntax = attributeSyntax; + private readonly AttributeArgumentSyntax[] arguments = attributeSyntax?.ArgumentList?.Arguments.Select(arg => arg).ToArray() ?? []; public virtual bool Matches(AttributeOwner other) { @@ -60,7 +54,7 @@ protected bool TryGetArgument(out TSyntax syntax) where TSyntax : Expre } } - syntax = null; + syntax = null!; return false; } @@ -79,10 +73,11 @@ protected bool TryEvaluateIntArgument(out int argument) protected bool TryEvaluateTypeArgument(out string argument) { - argument = null; - if (!TryGetArgument(out TypeSyntax expression)) + { + argument = null!; return false; + } argument = expression.GetText().ToString(); return true; @@ -90,10 +85,11 @@ protected bool TryEvaluateTypeArgument(out string argument) protected bool TryEvaluateStringArgument(out string argument) { - argument = null; - if (!TryGetArgument(out ExpressionSyntax expression)) + { + argument = null!; return false; + } return TryEvaluateString(expression, out argument); } @@ -112,13 +108,13 @@ InvocationExpressionSyntax invocation when invocation.Expression.GetText().ToStr // "A" + "B" BinaryExpressionSyntax binaryAdd when binaryAdd.Kind() == SyntaxKind.AddExpression - => TryEvaluateString(binaryAdd.Left, out var left) && TryEvaluateString(binaryAdd.Right, out var right) ? left + right : null, + => TryEvaluateString(binaryAdd.Left, out var left) && TryEvaluateString(binaryAdd.Right, out var right) ? left + right : null!, // $"A {B} C" InterpolatedStringExpressionSyntax interpolation - => TryEvaluateInterpolatedString(interpolation, out var interpolatedText) ? interpolatedText : null, + => TryEvaluateInterpolatedString(interpolation, out var interpolatedText) ? interpolatedText : null!, - _ => null + _ => null! }; return result is not null; @@ -142,7 +138,7 @@ private static bool TryEvaluateInterpolatedString(InterpolatedStringExpressionSy } else { - result = null; + result = null!; return false; } } diff --git a/Obsidian.SourceGenerators/Packets/Attributes/AttributeFactory.cs b/Obsidian.SourceGenerators/Packets/Attributes/AttributeFactory.cs index 7f7c512eb..c12a97d31 100644 --- a/Obsidian.SourceGenerators/Packets/Attributes/AttributeFactory.cs +++ b/Obsidian.SourceGenerators/Packets/Attributes/AttributeFactory.cs @@ -15,7 +15,7 @@ public static bool TryParse(AttributeSyntax attribute, out AttributeBehaviorBase if (attributeName.EndsWith("Attribute")) attributeName = attributeName.Substring(0, attributeName.Length - 9); - attributeBehaviorBase = methods.TryGetValue(attributeName, out FactoryMethod factoryMethod) ? factoryMethod(attribute) : null; + attributeBehaviorBase = methods.TryGetValue(attributeName, out FactoryMethod factoryMethod) ? factoryMethod(attribute) : null!; return attributeBehaviorBase is not null; } diff --git a/Obsidian.SourceGenerators/Packets/Attributes/ConditionBehavior.cs b/Obsidian.SourceGenerators/Packets/Attributes/ConditionBehavior.cs index 80d83f970..fdb731e76 100644 --- a/Obsidian.SourceGenerators/Packets/Attributes/ConditionBehavior.cs +++ b/Obsidian.SourceGenerators/Packets/Attributes/ConditionBehavior.cs @@ -69,12 +69,12 @@ private Property GetEndProperty(MethodBuildingContext context) { var sharedCondition = context.AllProperties .SkipWhile(prop => prop != context.Property) - .Select(prop => new { Property = prop, Attribute = prop.TryGetAttribute(out ConditionBehavior condition) ? condition : null }) + .Select(prop => new { Property = prop, Attribute = prop.TryGetAttribute(out ConditionBehavior? condition) ? condition : null }) .TakeWhile(entry => entry.Attribute?.Condition == Condition); foreach (var shared in sharedCondition.Skip(1)) { - shared.Attribute.Skip = true; + shared.Attribute!.Skip = true; } return sharedCondition.Last().Property; diff --git a/Obsidian.SourceGenerators/Packets/Attributes/CountTypeBehavior.cs b/Obsidian.SourceGenerators/Packets/Attributes/CountTypeBehavior.cs index 8e6bc1b94..c3ac05234 100644 --- a/Obsidian.SourceGenerators/Packets/Attributes/CountTypeBehavior.cs +++ b/Obsidian.SourceGenerators/Packets/Attributes/CountTypeBehavior.cs @@ -35,7 +35,7 @@ public override bool ModifyCollectionPrefixDeserialization(MethodBuildingContext } string getLength = $"{context.StreamName}.{readMethod}()"; - context.CodeBuilder.Line($"{context.DataName} = {context.Property.NewCollection(getLength)};"); + context.CodeBuilder.Line($"{context.DataName} = {context.Property.GetNewCollectionExpression(getLength)};"); return true; } } diff --git a/Obsidian.SourceGenerators/Packets/Attributes/DataFormatBehavior.cs b/Obsidian.SourceGenerators/Packets/Attributes/DataFormatBehavior.cs index abfdd643c..39ec0e399 100644 --- a/Obsidian.SourceGenerators/Packets/Attributes/DataFormatBehavior.cs +++ b/Obsidian.SourceGenerators/Packets/Attributes/DataFormatBehavior.cs @@ -17,7 +17,7 @@ public DataFormatBehavior(AttributeSyntax attributeSyntax) : base(attributeSynta public override bool Matches(AttributeOwner other) { return other.Flags.HasFlag(Flag) && - other.TryGetAttribute(out DataFormatBehavior format) && - format.Type == Type; + other.TryGetAttribute(out DataFormatBehavior? format) && + format!.Type == Type; } } diff --git a/Obsidian.SourceGenerators/Packets/Attributes/FixedLengthBehavior.cs b/Obsidian.SourceGenerators/Packets/Attributes/FixedLengthBehavior.cs index 8739f7aae..e36524323 100644 --- a/Obsidian.SourceGenerators/Packets/Attributes/FixedLengthBehavior.cs +++ b/Obsidian.SourceGenerators/Packets/Attributes/FixedLengthBehavior.cs @@ -34,7 +34,7 @@ public override bool ModifyCollectionPrefixDeserialization(MethodBuildingContext return false; } - context.CodeBuilder.Line($"{context.DataName} = {context.Property.NewCollection(Length.ToString())}"); + context.CodeBuilder.Line($"{context.DataName} = {context.Property.GetNewCollectionExpression(Length.ToString())}"); return true; } } diff --git a/Obsidian.SourceGenerators/Packets/Method.cs b/Obsidian.SourceGenerators/Packets/Method.cs index 13628dd43..3380da063 100644 --- a/Obsidian.SourceGenerators/Packets/Method.cs +++ b/Obsidian.SourceGenerators/Packets/Method.cs @@ -2,28 +2,11 @@ namespace Obsidian.SourceGenerators.Packets; -internal sealed class Method : AttributeOwner +internal sealed class Method(string name, string type, AttributeBehaviorBase[] attributes) + : AttributeOwner(AggregateFlags(attributes) | AttributeFlags.Field, attributes) { - public string Name { get; } - public string Type { get; } - - public Method(string name, string type, AttributeBehaviorBase[] attributes) - { - Name = name; - Type = type; - Attributes = attributes; - - if (Type.Contains('.')) - { - Type = Type.Substring(Type.LastIndexOf('.') + 1); - } - - Flags = AttributeFlags.Field; - for (int i = 0; i < attributes.Length; i++) - { - Flags |= attributes[i].Flag; - } - } + public string Name { get; } = name; + public string Type { get; } = GetRelativeTypeName(type); public override string ToString() { diff --git a/Obsidian.SourceGenerators/Packets/MethodsRegistry.cs b/Obsidian.SourceGenerators/Packets/MethodsRegistry.cs index 5be823e22..6ce032ffa 100644 --- a/Obsidian.SourceGenerators/Packets/MethodsRegistry.cs +++ b/Obsidian.SourceGenerators/Packets/MethodsRegistry.cs @@ -32,7 +32,7 @@ public bool TryGetReadMethod(Property property, bool collection, out Method meth private bool TryGetMethod(IEnumerable source, Property property, bool collection, out Method outMethod) { - string propertyType = collection ? property.CollectionType : property.Type; + string? propertyType = collection ? property.CollectionType : property.Type; foreach (Method method in source) { if (method.Type != propertyType) @@ -48,7 +48,7 @@ private bool TryGetMethod(IEnumerable source, Property property, bool co return true; } - outMethod = null; + outMethod = null!; return false; } @@ -90,7 +90,7 @@ public void Offer(GeneratorExecutionContext context, MethodDeclarationSyntax met private bool TryGetWriteMethodType(GeneratorExecutionContext context, MethodDeclarationSyntax method, out string type) { - type = null; + type = null!; var parameters = method.ParameterList.Parameters; if (parameters.Count == 0) @@ -111,7 +111,7 @@ private bool TryGetWriteMethodType(GeneratorExecutionContext context, MethodDecl return false; } - type = parameter.Type.ToString(); + type = parameter.Type!.ToString(); return true; } diff --git a/Obsidian.SourceGenerators/Packets/Property.cs b/Obsidian.SourceGenerators/Packets/Property.cs index 8a950bc91..cf6a8c6f0 100644 --- a/Obsidian.SourceGenerators/Packets/Property.cs +++ b/Obsidian.SourceGenerators/Packets/Property.cs @@ -7,111 +7,120 @@ namespace Obsidian.SourceGenerators.Packets; internal sealed class Property : AttributeOwner { - public PreactionCallback Writing; - public PostactionCallback Written; - public PreactionCallback Reading; - public PostactionCallback Read; - - public string Name { get; private set; } - public string Type { get; set; } - public INamedTypeSymbol ContainingType { get; set; } - public MemberDeclarationSyntax DeclarationSyntax { get; set; } - public bool IsGeneric { get; private set; } - public bool IsCollection { get; set; } - public string CollectionType { get; set; } - public string Length { get; set; } - public int Order { get; set; } - - public Property() + public PreactionCallback? Writing; + public PostactionCallback? Written; + public PreactionCallback? Reading; + public PostactionCallback? Read; + + public string Name { get; } + public string Type { get; private set; } + public INamedTypeSymbol ContainingType { get; } + public MemberDeclarationSyntax DeclarationSyntax { get; } + public bool IsGeneric { get; } + public bool IsCollection => CollectionType is not null; + public string? CollectionType { get; } + public string? Length { get; } + public int Order { get; } + + private Property(Property property) : base(property.Flags, property.Attributes) { + Type = property.Type; + DeclarationSyntax = property.DeclarationSyntax; + CollectionType = property.CollectionType; + ContainingType = property.ContainingType; + IsGeneric = property.IsGeneric; + Length = property.Length; + Order = property.Order; + Name = property.Name; + Writing = property.Writing; + Written = property.Written; + Reading = property.Reading; + Read = property.Read; + } + + private Property(string name, MemberDeclarationSyntax declaration, INamedTypeSymbol containingType, TypeSyntax type, AttributeBehaviorBase[] attributes) + : base(AggregateFlags(attributes), attributes) + { + Name = name; + DeclarationSyntax = declaration; + ContainingType = containingType; + (Type, CollectionType, Length) = DetermineType(type); + Order = DetermineOrder(attributes); + IsGeneric = containingType.TypeParameters.Any(genericType => genericType.Name == Type); } public Property(FieldDeclarationSyntax field, ISymbol symbol) + : this(field.Declaration.Variables.First().Identifier.Text, field, symbol.ContainingType, field.Declaration.Type, CollectAttributes(field)) { - Name = field.Declaration.Variables.First().Identifier.Text; - DeclarationSyntax = field; - ContainingType = symbol.ContainingType; - SetType(field.Declaration.Type); - IsGeneric = ContainingType.TypeParameters.Any(genericType => genericType.Name == Type); - SetAttributes(field.AttributeLists.SelectMany(list => list.Attributes)); } public Property(PropertyDeclarationSyntax property, ISymbol symbol) + : this(property.Identifier.Text, property, symbol.ContainingType, property.Type, CollectAttributes(property)) { - Name = property.Identifier.Text; - DeclarationSyntax = property; - ContainingType = symbol.ContainingType; - SetType(property.Type); - IsGeneric = ContainingType.TypeParameters.Any(genericType => genericType.Name == Type); - SetAttributes(property.AttributeLists.SelectMany(list => list.Attributes)); } - private void SetType(TypeSyntax typeSyntax) + internal Property(string name, string type, AttributeFlags flags, AttributeBehaviorBase[] attributes) + : base(flags, attributes) { - Type = typeSyntax.ToString(); - if (Type.Contains('.')) - { - Type = Type.Substring(Type.IndexOf('.') + 1); - } - if (Type.EndsWith("[]")) + Name = name; + Type = type; + ContainingType = null!; + DeclarationSyntax = null!; + } + + private static (string Type, string? CollectionType, string? Length) DetermineType(TypeSyntax typeSyntax) + { + string type = GetRelativeTypeName(typeSyntax.ToString()); + + if (type.EndsWith("[]")) { - CollectionType = Type; - Type = Type.Substring(0, Type.Length - 2); - IsCollection = true; - Length = "Length"; + return (type.Substring(0, type.Length - 2), type, "Length"); } - else if (Type.EndsWith(">")) + + if (type.EndsWith(">")) { - CollectionType = Type; - int typeStart = Type.IndexOf('<') + 1; - Type = Type.Substring(typeStart, Type.Length - typeStart - 1); - IsCollection = true; - Length = "Count"; + int genericArgumentIndex = type.IndexOf('<') + 1; + string genericArgument = type.Substring(genericArgumentIndex, type.Length - genericArgumentIndex - 1); + return (genericArgument, type, "Count"); } + + return (type, null, null); } - private void SetAttributes(IEnumerable attributes) + private static AttributeBehaviorBase[] CollectAttributes(MemberDeclarationSyntax declaration) { - Attributes = AttributeFactory.ParseValidAttributesSorted(attributes); + IEnumerable attributes = declaration.AttributeLists.SelectMany(list => list.Attributes); + return AttributeFactory.ParseValidAttributesSorted(attributes); + } - Flags = AttributeFlags.None; - for (int i = 0; i < Attributes.Length; i++) + private static int DetermineOrder(AttributeBehaviorBase[] attributes) + { + for (int i = 0; i < attributes.Length; i++) { - Flags |= Attributes[i].Flag; - - if (Attributes[i] is FieldBehavior field) + if (attributes[i] is FieldBehavior field) { - Order = field.Order; + return field.Order; } } + + return default; } - public string NewCollection(string length) + public string GetNewCollectionExpression(string length) { if (!IsCollection) + { throw new InvalidOperationException(); + } - return CollectionType.EndsWith("[]") ? + return CollectionType!.EndsWith("[]") ? $"new {Type}[{length}]" : $"new {CollectionType}({length})"; } public Property Clone() { - return new Property - { - Type = Type, - DeclarationSyntax = DeclarationSyntax, - CollectionType = CollectionType, - ContainingType = ContainingType, - IsCollection = IsCollection, - IsGeneric = IsGeneric, - Length = Length, - Order = Order, - Attributes = Attributes, - Flags = Flags, - Name = Name - }; + return new Property(this); } public Property CloneWithType(string type) diff --git a/Obsidian.SourceGenerators/Packets/SerializationMethodsGenerator.cs b/Obsidian.SourceGenerators/Packets/SerializationMethodsGenerator.cs index 0c3527bfd..17810a908 100644 --- a/Obsidian.SourceGenerators/Packets/SerializationMethodsGenerator.cs +++ b/Obsidian.SourceGenerators/Packets/SerializationMethodsGenerator.cs @@ -6,21 +6,13 @@ namespace Obsidian.SourceGenerators.Packets; [Generator] public partial class SerializationMethodsGenerator : ISourceGenerator { - private static Property varInt; // Used for default collection length prefix + private static Property varInt = null!; // Used for default collection length prefix public void Initialize(GeneratorInitializationContext context) { context.RegisterForSyntaxNotifications(() => new SyntaxProvider()); - varInt = new Property - { - Type = "int", - Attributes = - [ - new VarLengthBehavior(null) - ], - Flags = AttributeFlags.Field | AttributeFlags.VarLength - }; + varInt = new Property("VarInt", "int", AttributeFlags.Field | AttributeFlags.VarLength, [new VarLengthBehavior(null!)]); } public void Execute(GeneratorExecutionContext context) @@ -54,21 +46,30 @@ private void DangerousExecute(GeneratorExecutionContext context) { foreach (VariableDeclaratorSyntax variable in field.Declaration.Variables) { - ISymbol symbol = model.GetDeclaredSymbol(variable); - properties.Add(new Property(field, symbol)); + if (model.GetDeclaredSymbol(variable) is ISymbol symbol) + { + properties.Add(new Property(field, symbol)); + } } } else if (member is PropertyDeclarationSyntax property) { - ISymbol symbol = model.GetDeclaredSymbol(member); - properties.Add(new Property(property, symbol)); + if (model.GetDeclaredSymbol(member) is ISymbol symbol) + { + properties.Add(new Property(property, symbol)); + } } } // Generate partial classes - foreach (var group in properties.GroupBy(field => field.ContainingType)) + var typeToProperties = properties + .GroupBy(static field => field.ContainingType, SymbolEqualityComparer.Default); + foreach ((ISymbol? symbol, List fields) in typeToProperties) { - var @class = group.Key; + if (symbol is not INamedTypeSymbol @class) + { + continue; + } if (@class.IsStatic || @class.DeclaredAccessibility != Accessibility.Public) { @@ -76,7 +77,6 @@ private void DangerousExecute(GeneratorExecutionContext context) continue; } - var fields = group.ToList(); string classSource = ProcessClass(@class, fields, syntaxProvider); context.AddSource($"{@class.Name}.Serialization.cs", SourceText.From(classSource, Encoding.UTF8)); } @@ -87,24 +87,27 @@ private string ProcessClass(INamedTypeSymbol classSymbol, List fields, fields.Sort((a, b) => a.Order.CompareTo(b.Order)); string @namespace = classSymbol.ContainingNamespace.ToDisplayString(); - string className = classSymbol.IsGenericType ? $"{classSymbol.Name}<{string.Join(", ", classSymbol.TypeParameters.Select(parameter => parameter.Name))}>" : classSymbol.Name; + string className = classSymbol.IsGenericType + ? $"{classSymbol.Name}<{string.Join(", ", classSymbol.TypeParameters.Select(parameter => parameter.Name))}>" + : classSymbol.Name; var interfaces = classSymbol.AllInterfaces; bool clientbound = interfaces.Any(@interface => @interface.Name == Vocabulary.ClientboundInterface); bool serverbound = interfaces.Any(@interface => @interface.Name == Vocabulary.ServerboundInterface); var methods = classSymbol.GetMembers().OfType(); - var source = new CodeBuilder(); var usings = new HashSet(); - foreach (SyntaxReference declaration in classSymbol.DeclaringSyntaxReferences) { SyntaxNode root = declaration.GetSyntax().GetRoot(); - foreach (var usingDirective in root.DescendantNodes().OfType()) + foreach (SyntaxNode child in root.DescendantNodes()) { - usings.Add(usingDirective.Name.ToString()); + if (child is UsingDirectiveSyntax { Name: NameSyntax name }) + { + usings.Add(name.ToString()); + } } } @@ -298,7 +301,7 @@ private bool TrySerializePropertyCollection(string streamName, Property property return true; } - private bool TrySerializeProperty(string streamName, Property property, List properties, CodeBuilder builder, SyntaxProvider syntaxProvider, Method writeMethod = null) + private bool TrySerializeProperty(string streamName, Property property, List properties, CodeBuilder builder, SyntaxProvider syntaxProvider, Method? writeMethod = null) { if (writeMethod is null) syntaxProvider.Methods.TryGetWriteMethod(property, out writeMethod); @@ -382,7 +385,7 @@ private bool TryReadPropertyCollection(string streamName, string dataName, Prope return false; } string getLength = $"{streamName}.{readMethod}()"; - builder.Line($"{dataName} = {property.NewCollection(getLength)};"); + builder.Line($"{dataName} = {property.GetNewCollectionExpression(getLength)};"); LOOP: builder.Statement($"for (int i = 0; i < {dataName}.{property.Length}; i++)"); @@ -411,7 +414,7 @@ private bool TryReadPropertyCollection(string streamName, string dataName, Prope return true; } - private bool TryReadProperty(string streamName, string dataName, Property property, List properties, CodeBuilder builder, SyntaxProvider syntaxProvider, Method readMethod = null) + private bool TryReadProperty(string streamName, string dataName, Property property, List properties, CodeBuilder builder, SyntaxProvider syntaxProvider, Method? readMethod = null) { if (readMethod is null) syntaxProvider.Methods.TryGetReadMethod(property, out readMethod); @@ -482,7 +485,7 @@ public static SyntaxNode GetRoot(this SyntaxNode syntaxNode) return syntaxNode; } - public static bool Execute(this PreactionCallback callback, MethodBuildingContext context) + public static bool Execute(this PreactionCallback? callback, MethodBuildingContext context) { if (callback is null) return false; @@ -496,7 +499,7 @@ public static bool Execute(this PreactionCallback callback, MethodBuildingContex return false; } - public static void Execute(this PostactionCallback callback, MethodBuildingContext context) + public static void Execute(this PostactionCallback? callback, MethodBuildingContext context) { callback?.Invoke(context); } diff --git a/Obsidian.SourceGenerators/Registry/EntityGenerator.cs b/Obsidian.SourceGenerators/Registry/EntityGenerator.cs index 3b729f1ac..fab6beb91 100644 --- a/Obsidian.SourceGenerators/Registry/EntityGenerator.cs +++ b/Obsidian.SourceGenerators/Registry/EntityGenerator.cs @@ -2,6 +2,7 @@ using Obsidian.SourceGenerators.Registry.Models; using System.Collections.Immutable; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Text.Json; using System.Xml.Schema; @@ -120,8 +121,8 @@ private void GenerateClasses(List classes, JsonDocument document, S .Type($"public partial class {@class.Symbol.Name}"); builder.Indent().Append("public override EntityDimension Dimension { get; protected set; } = new() { ") - .Append($"Width = {widthElement.GetSingle()}f, ") - .Append($"Height = {heightElement.GetSingle()}f }}; ") + .Append($"Width = {widthElement.GetSingle().ToString(CultureInfo.InvariantCulture)}f, ") + .Append($"Height = {heightElement.GetSingle().ToString(CultureInfo.InvariantCulture)}f }}; ") .Line() .Line(); @@ -153,7 +154,7 @@ private void GenerateClasses(List classes, JsonDocument document, S foreach (var attrElement in attributesElement.EnumerateObject()) { var name = attrElement.Name; - var value = attrElement.Value.GetSingle(); + var value = attrElement.Value.GetSingle().ToString(CultureInfo.InvariantCulture); builder.Line($"{{ \"{name}\", {value}f }}, "); } diff --git a/Obsidian.SourceGenerators/Registry/Models/Block.cs b/Obsidian.SourceGenerators/Registry/Models/Block.cs index fc80113fc..c39417c68 100644 --- a/Obsidian.SourceGenerators/Registry/Models/Block.cs +++ b/Obsidian.SourceGenerators/Registry/Models/Block.cs @@ -56,8 +56,13 @@ private static (int baseId, int defaultId, int stateCount, Dictionary(); - foreach (var properties in jsonElement.EnumerateObject()) - values.Add(properties.Value.GetString().ToPascalCase()); + foreach (JsonProperty jsonProperty in jsonElement.EnumerateObject()) + { + if (jsonProperty.Value.GetString() is string propertyValue) + { + values.Add(propertyValue.ToPascalCase()); + } + } props.Add(id, values); } diff --git a/Obsidian.SourceGenerators/Registry/RegistryAssetsGenerator.cs b/Obsidian.SourceGenerators/Registry/RegistryAssetsGenerator.cs index 6f2099a09..1e7d4bafa 100644 --- a/Obsidian.SourceGenerators/Registry/RegistryAssetsGenerator.cs +++ b/Obsidian.SourceGenerators/Registry/RegistryAssetsGenerator.cs @@ -1,9 +1,6 @@ using Obsidian.SourceGenerators.Registry.Models; using System.Collections.Immutable; -using System.Diagnostics; -using System.Globalization; using System.IO; -using System.Text.Json; namespace Obsidian.SourceGenerators.Registry; @@ -12,34 +9,28 @@ public sealed partial class RegistryAssetsGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { - //if (!Debugger.IsAttached) - // Debugger.Launch(); - - CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; - var jsonFiles = context.AdditionalTextsProvider .Where(file => file.Path.EndsWith(".json")) .Select(static (file, ct) => (name: Path.GetFileNameWithoutExtension(file.Path), content: file.GetText(ct)!.ToString())); var compilation = context.CompilationProvider.Combine(jsonFiles.Collect()); - context.RegisterSourceOutput(compilation, this.Generate); + context.RegisterSourceOutput(compilation, Generate); } private void Generate(SourceProductionContext context, (Compilation compilation, ImmutableArray<(string name, string json)> files) output) { - var asm = output.compilation.AssemblyName; - + var assembly = output.compilation.AssemblyName; var assets = Assets.Get(output.files, context); - if (asm == "Obsidian") + if (assembly == "Obsidian") { GenerateTags(assets, context); GenerateItems(assets, context); GenerateBlockIds(assets, context); GenerateCodecs(assets, context); } - else if (asm == "Obsidian.API") + else if (assembly == "Obsidian.API") { GenerateMaterials(assets, context); }