~ruther/NosSmooth

90aff7c9898496952a8c47c7db30989d180f32f8 — František Boháček 3 years ago df3d5df
feat: add checking parameter method for the generator
M Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/IParameterGenerator.cs => Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/IParameterGenerator.cs +8 -0
@@ 24,6 24,14 @@ namespace NosSmooth.PacketSerializersGenerator.AttributeGenerators
        public bool ShouldHandle(ParameterInfo parameter);

        /// <summary>
        /// Checks the given parameter, returns an error if the parameter cannot be processed.
        /// </summary>
        /// <param name="packet">The packet.</param>
        /// <param name="parameter">The parameter.</param>
        /// <returns>An error, if any.</returns>
        public IError? CheckParameter(PacketInfo packet, ParameterInfo parameter);

        /// <summary>
        /// Generate part for the Serializer method to serialize the given parameter.
        /// </summary>
        /// <param name="textWriter">The text writer to write the code to.</param>

M Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/PacketContextListAttributeGenerator.cs => Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/PacketContextListAttributeGenerator.cs +15 -6
@@ 27,6 27,18 @@ public class PacketContextListAttributeGenerator : IParameterGenerator
        => parameter.Attributes.Any(x => x.FullName == PacketListIndexAttributeFullName);

    /// <inheritdoc />
    public IError? CheckParameter(PacketInfo packet, ParameterInfo parameter)
    {
        var error = ParameterChecker.CheckHasOneAttribute(packet, parameter);
        if (error is not null)
        {
            return error;
        }

        return ParameterChecker.CheckOptionalIsNullable(packet, parameter);
    }

    /// <inheritdoc />
    public IError? GenerateSerializerPart(IndentedTextWriter textWriter, PacketInfo packetInfo)
    {
        var generator = new ConverterSerializationGenerator(textWriter);


@@ 76,11 88,7 @@ public class PacketContextListAttributeGenerator : IParameterGenerator
        // add optional if
        if (parameter.IsOptional())
        {
            var error = generator.StartOptionalCheck(parameter, packetInfo.Name);
            if (error is not null)
            {
                return error;
            }
            generator.StartOptionalCheck(parameter, packetInfo.Name);
        }

        var afterSeparator = attribute.GetNamedValue<char?>("AfterSeparator", null);


@@ 96,7 104,8 @@ public class PacketContextListAttributeGenerator : IParameterGenerator
        var innerSeparator = attribute.GetNamedValue<char>("InnerSeparator", '.');
        generator.PrepareLevel(innerSeparator);

        generator.DeserializeAndCheck($"{packetInfo.Namespace}.{packetInfo.Name}", parameter, packetInfo.Parameters.IsLast);
        generator.DeserializeAndCheck
            ($"{packetInfo.Namespace}.{packetInfo.Name}", parameter, packetInfo.Parameters.IsLast);
        generator.RemovePreparedLevel();
        generator.PopLevel();
        if (!parameter.Nullable)

M Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/PacketGreedyIndexAttributeGenerator.cs => Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/PacketGreedyIndexAttributeGenerator.cs +13 -5
@@ 34,6 34,18 @@ public class PacketGreedyIndexAttributeGenerator : IParameterGenerator
        => parameter.Attributes.Any(x => x.FullName == PacketIndexAttributeFullName);

    /// <inheritdoc />
    public IError? CheckParameter(PacketInfo packet, ParameterInfo parameter)
    {
        var error = ParameterChecker.CheckHasOneAttribute(packet, parameter);
        if (error is not null)
        {
            return error;
        }

        return ParameterChecker.CheckOptionalIsNullable(packet, parameter);
    }

    /// <inheritdoc />
    public IError? GenerateSerializerPart(IndentedTextWriter textWriter, PacketInfo packetInfo)
        => _basicAttributeGenerator.GenerateSerializerPart(textWriter, packetInfo);



@@ 50,11 62,7 @@ public class PacketGreedyIndexAttributeGenerator : IParameterGenerator
        // add optional if
        if (parameter.IsOptional())
        {
            var error = generator.StartOptionalCheck(parameter, packetInfo.Name);
            if (error is not null)
            {
                return error;
            }
            generator.StartOptionalCheck(parameter, packetInfo.Name);
        }

        var afterSeparator = attribute.GetNamedValue<char?>("AfterSeparator", null);

M Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/PacketIndexAttributeGenerator.cs => Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/PacketIndexAttributeGenerator.cs +13 -6
@@ 24,6 24,18 @@ public class PacketIndexAttributeGenerator : IParameterGenerator
        => parameter.Attributes.Any(x => x.FullName == PacketIndexAttributeFullName);

    /// <inheritdoc />
    public IError? CheckParameter(PacketInfo packet, ParameterInfo parameter)
    {
        var error = ParameterChecker.CheckHasOneAttribute(packet, parameter);
        if (error is not null)
        {
            return error;
        }

        return ParameterChecker.CheckOptionalIsNullable(packet, parameter);
    }

    /// <inheritdoc />
    public IError? GenerateSerializerPart(IndentedTextWriter textWriter, PacketInfo packetInfo)
    {
        bool pushedLevel = false;


@@ 85,11 97,7 @@ public class PacketIndexAttributeGenerator : IParameterGenerator
        // add optional if
        if (parameter.IsOptional())
        {
            var error = generator.StartOptionalCheck(parameter, packetInfo.Name);
            if (error is not null)
            {
                return error;
            }
            generator.StartOptionalCheck(parameter, packetInfo.Name);
        }

        var afterSeparator = attribute.GetNamedValue<char?>("AfterSeparator", null);


@@ 114,7 122,6 @@ public class PacketIndexAttributeGenerator : IParameterGenerator
        }

        generator.AssignLocalVariable(parameter, false);

        if (pushedLevel)
        {
            generator.ReadToLastToken();

M Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/PacketListIndexAttributeGenerator.cs => Core/NosSmooth.PacketSerializersGenerator/AttributeGenerators/PacketListIndexAttributeGenerator.cs +13 -5
@@ 29,6 29,18 @@ public class PacketListIndexAttributeGenerator : IParameterGenerator
        => parameter.Attributes.Any(x => x.FullName == PacketListIndexAttributeFullName);

    /// <inheritdoc />
    public IError? CheckParameter(PacketInfo packet, ParameterInfo parameter)
    {
        var error = ParameterChecker.CheckHasOneAttribute(packet, parameter);
        if (error is not null)
        {
            return error;
        }

        return ParameterChecker.CheckOptionalIsNullable(packet, parameter);
    }

    /// <inheritdoc />
    public IError? GenerateSerializerPart(IndentedTextWriter textWriter, PacketInfo packetInfo)
    {
        var generator = new ConverterSerializationGenerator(textWriter);


@@ 80,11 92,7 @@ public class PacketListIndexAttributeGenerator : IParameterGenerator
        // add optional if
        if (parameter.IsOptional())
        {
            var error = generator.StartOptionalCheck(parameter, packetInfo.Name);
            if (error is not null)
            {
                return error;
            }
            generator.StartOptionalCheck(parameter, packetInfo.Name);
        }

        var afterSeparator = attribute.GetNamedValue<char?>("AfterSeparator", null);

M Core/NosSmooth.PacketSerializersGenerator/ConverterDeserializationGenerator.cs => Core/NosSmooth.PacketSerializersGenerator/ConverterDeserializationGenerator.cs +1 -16
@@ 157,27 157,12 @@ if ({resultVariableName}.Entity is null) {{
    /// </summary>
    /// <param name="parameter">The parameter information.</param>
    /// <param name="packetName">The name of the packet.</param>
    /// <returns>An error, if any.</returns>
    public IError? StartOptionalCheck(ParameterInfo parameter, string packetName)
    public void StartOptionalCheck(ParameterInfo parameter, string packetName)
    {
        if (!parameter.Nullable)
        {
            return new DiagnosticError
            (
                "SG0006",
                "Optional parameters must be nullable",
                "The parameter {0} in {1} has to be nullable, because it is optional.",
                parameter.Parameter.SyntaxTree,
                parameter.Parameter.FullSpan,
                new List<object?>(new[] { parameter.Name, packetName })
            );
        }

        // serialize this parameter only if we are not on the last token.
        _textWriter.WriteLine($"if (!(stringEnumerator.IsOnLastToken() ?? true))");
        _textWriter.WriteLine("{");
        _textWriter.Indent++;
        return null;
    }

    /// <summary>

M Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs => Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs +16 -4
@@ 136,10 136,16 @@ private IResultError? CheckDeserializationResult<T>(Result<T> result, string pro
            {
                if (generator.ShouldHandle(parameter))
                {
                    var result = generator.GenerateSerializerPart(textWriter, _packetInfo);
                    if (result is not null)
                    var checkError = generator.CheckParameter(_packetInfo, parameter);
                    if (checkError is not null)
                    {
                        return result;
                        return checkError;
                    }

                    var serializerError = generator.GenerateSerializerPart(textWriter, _packetInfo);
                    if (serializerError is not null)
                    {
                        return serializerError;
                    }

                    handled = true;


@@ 192,7 198,7 @@ private IResultError? CheckDeserializationResult<T>(Result<T> result, string pro
            {
                return new DiagnosticError
                (
                    "SG0004",
                    "SGInd",
                    "Same packet index",
                    "There were two parameters of the same packet index {0} on property {1} in packet {2}, that is not supported.",
                    parameter.Attributes.First().Attribute.SyntaxTree,


@@ 214,6 220,12 @@ private IResultError? CheckDeserializationResult<T>(Result<T> result, string pro
            {
                if (generator.ShouldHandle(parameter))
                {
                    var checkError = generator.CheckParameter(_packetInfo, parameter);
                    if (checkError is not null)
                    {
                        return checkError;
                    }

                    var result = generator.GenerateDeserializerPart(textWriter, _packetInfo);
                    if (result is not null)
                    {

A Core/NosSmooth.PacketSerializersGenerator/ParameterChecker.cs => Core/NosSmooth.PacketSerializersGenerator/ParameterChecker.cs +72 -0
@@ 0,0 1,72 @@
//
//  ParameterChecker.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.PacketSerializersGenerator.Data;
using NosSmooth.PacketSerializersGenerator.Errors;
using NosSmooth.PacketSerializersGenerator.Extensions;

namespace NosSmooth.PacketSerializersGenerator;

/// <summary>
/// Helpers for checking packet parameters.
/// </summary>
public static class ParameterChecker
{
    /// <summary>
    /// Checks that the given parameter has exactly one packet attribute.
    /// </summary>
    /// <param name="packetInfo">The packet.</param>
    /// <param name="parameter">The parameter.</param>
    /// <returns>An error, if any.</returns>
    public static IError? CheckHasOneAttribute(PacketInfo packetInfo, ParameterInfo parameter)
    {
        if (parameter.Attributes.Count > 1)
        {
            return new DiagnosticError
            (
                "SGAttr",
                "Packet constructor parameter with multiple packet attributes",
                "Found multiple packet attributes on parameter {0} in {1}. That is not supported for this type of packet attribute.",
                parameter.Parameter.SyntaxTree,
                parameter.Parameter.FullSpan,
                new List<object?>
                (
                    new[]
                    {
                        parameter.Name,
                        packetInfo.Name
                    }
                )
            );
        }

        return null;
    }

    /// <summary>
    /// Checks that the given parameter is nullable, if it is optional.
    /// </summary>
    /// <param name="packetInfo">The packet.</param>
    /// <param name="parameter">The parameter.</param>
    /// <returns>An error, if any.</returns>
    public static IError? CheckOptionalIsNullable(PacketInfo packetInfo, ParameterInfo parameter)
    {
        if (parameter.IsOptional() && !parameter.Nullable)
        {
            return new DiagnosticError
            (
                "SGNull",
                "Optional parameters must be nullable",
                "The parameter {0} in {1} has to be nullable, because it is optional.",
                parameter.Parameter.SyntaxTree,
                parameter.Parameter.FullSpan,
                new List<object?>(new[] { parameter.Name, packetInfo.Name })
            );
        }

        return null;
    }
}
\ No newline at end of file

M Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs => Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs +2 -2
@@ 131,7 131,7 @@ public class SourceGenerator : ISourceGenerator
        {
            return new DiagnosticError
            (
                "SG0001",
                "SGConst",
                "Packet without constructor",
                "The packet class {0} does not have any constructors to use for packet serializer.",
                packetClass.SyntaxTree,


@@ 219,7 219,7 @@ public class SourceGenerator : ISourceGenerator
        {
            return new DiagnosticError
            (
                "SG0003",
                "SGAttr",
                "Packet constructor parameter without packet attribute",
                "Could not find PacketIndexAttribute on {0} parameter in class {1}. Parameters without PacketIndexAttribute aren't allowed.",
                parameter.SyntaxTree,

Do not follow this link