コード例 #1
0
ファイル: SourceGenerator.cs プロジェクト: 0000duck/MiniRTS
 private static void ReportGeneratorDiagnostics(GeneratorExecutionContext context, SourceTextGenerator generator)
 => generator.Diagnostics.ToList().ForEach(diagnostic => context.ReportDiagnostic(diagnostic));
コード例 #2
0
        public void Execute(GeneratorExecutionContext context)
        {
            var fields = GetAircraftFields(context).ToList();

            var builder = new StringBuilder();

            builder.Append(@"
using System;
using Microsoft.Extensions.Logging;
using Microsoft.FlightSimulator.SimConnect;

namespace FlightRecorder.Client.SimConnectMSFS
{
    public partial class Connector
    {");

            builder.Append(@"
        private void RegisterAircraftPositionDefinition()
        {
            RegisterDataDefinition<AircraftPositionStruct>(DEFINITIONS.AircraftPosition");
            foreach ((_, _, var variable, var unit, var type, _, _) in fields)
            {
                builder.Append($@",
                (""{variable}"", ""{unit}"", (SIMCONNECT_DATATYPE){type})");
            }
            builder.Append(@"
            );
        }
");

            builder.Append(@"
        private void RegisterAircraftPositionSetDefinition()
        {
            RegisterDataDefinition<AircraftPositionSetStruct>(DEFINITIONS.AircraftPositionSet");
            foreach ((_, _, var variable, var unit, var type, var setType, _) in fields)
            {
                if (setType == null || setType == SetTypeDefault)
                {
                    builder.Append($@",
                (""{variable}"", ""{unit}"", (SIMCONNECT_DATATYPE){type})");
                }
            }
            builder.Append(@"
            );
        }
");

            builder.Append(@"
        private void RegisterEvents()
        {");
            var eventId = InitialEventID;

            foreach ((_, _, var variable, var unit, var type, var setType, var setBy) in fields)
            {
                if (setType == SetTypeEvent)
                {
                    // TODO: warning if setBy is empty
                    builder.Append($@"
            logger.LogDebug(""Register event {{eventName}} to ID {{eventID}}"", ""{setBy}"", {eventId});
            simconnect.MapClientEventToSimEvent((EVENTS){eventId}, ""{setBy}"");");
                    eventId++;
                }
            }
            builder.Append(@"
        }
");
            builder.Append(@"
        public void TriggerEvents(AircraftPositionStruct current, AircraftPositionStruct expected)
        {");
            eventId = InitialEventID;
            foreach ((_, var name, var variable, var unit, var type, var setType, var setBy) in fields)
            {
                if (setType == SetTypeEvent)
                {
                    // TODO: warning if setBy is empty
                    builder.Append($@"
            if (current.{name} != expected.{name})
            {{
                logger.LogDebug(""Trigger event {{eventName}}"", ""{setBy}"");
                simconnect.TransmitClientEvent(SimConnect.SIMCONNECT_OBJECT_ID_USER, (EVENTS){eventId}, 0, GROUPS.GENERIC, SIMCONNECT_EVENT_FLAG.GROUPID_IS_PRIORITY);
            }}
");
                    eventId++;
                }
            }
            builder.Append(@"
        }
");

            builder.Append(@"
    }
}");

            context.AddSource("ConnectorGenerator", SourceText.From(builder.ToString(), Encoding.UTF8));
        }
コード例 #3
0
 // ReSharper disable once InconsistentNaming
 public static string[] GetMSBuildItems(this GeneratorExecutionContext context, string name) =>
 context
 .AdditionalFiles
 .Where(f =>
コード例 #4
0
ファイル: SourceGenerator.cs プロジェクト: 0000duck/MiniRTS
 private static void ReportProgress(GeneratorExecutionContext context, int count)
 => context.ReportDiagnostic(
     Diagnostic.Create(new DiagnosticDescriptor("GENS01", "System Generator", $"Extended {count} systems",
                                                "Generator", DiagnosticSeverity.Warning, true), null));
コード例 #5
0
        private string GenerateBody(GeneratorExecutionContext context, TypeDeclarationSyntax tds, bool snakeCase, List <string> externalInheritances, string ns)
        {
            var body = new List <string>();

            var members = context.ParseMembers(tds, false, externalInheritances, out bool isPositionalRecord);

            if (!context.CancellationToken.IsCancellationRequested)
            {
                var arrayPropertyType = typeof(ArrayPropertyAttribute);

                foreach (var member in members)
                {
                    var(symbol, typeSymbol, nullable) = member;

                    // Object field name
                    var fieldName = symbol.Name;

                    // Data field name
                    var dataFieldName = snakeCase ? fieldName.ToSnakeCase() : fieldName;

                    // Field type name
                    var typeName = typeSymbol.GetTypeName(nullable, ns);

                    // ArrayProperty attribute data
                    var arrayData = symbol.GetAttributeData(arrayPropertyType.FullName);

                    // Value part
                    string valuePart;

                    if (typeSymbol.IsSimpleType())
                    {
                        valuePart = $@"dic.GetExact<{typeName}>(""{dataFieldName}"")";

                        if (typeSymbol.Name == "String" && !nullable)
                        {
                            valuePart += "!";
                        }
                    }
                    else if (typeSymbol.TypeKind == TypeKind.Enum)
                    {
                        // Enum item type
                        var enumSymbol = (INamedTypeSymbol)typeSymbol;
                        var enumType   = enumSymbol.EnumUnderlyingType?.Name ?? "Byte";
                        valuePart = $@"({typeName})dic.GetExact<{enumType}>(""{dataFieldName}"")";
                    }
                    else if (typeSymbol.TypeKind == TypeKind.Array)
                    {
                        // Array type
                        var arraySymbol    = (IArrayTypeSymbol)typeSymbol;
                        var itemTypeSymbol = arraySymbol.ElementType;
                        if (!itemTypeSymbol.IsSimpleType())
                        {
                            continue;
                        }

                        // Splitter
                        var splitter = Extensions.CharToString(arrayData?.GetValue <char?>("Splitter") ?? ',');

                        var arrayType = itemTypeSymbol.Name;
                        if (arrayType.Equals("String"))
                        {
                            valuePart = $@"StringUtils.AsEnumerable(dic.GetExact<string?>(""{dataFieldName}""), '{splitter}').ToArray()";
                        }
                        else
                        {
                            valuePart = $@"StringUtils.AsEnumerable<{arrayType}>(dic.GetExact<string?>(""{dataFieldName}""), '{splitter}').ToArray()";
                        }
                    }
                    else if (typeSymbol.IsList())
                    {
                        // Item type
                        var listSymbol     = (INamedTypeSymbol)typeSymbol;
                        var itemTypeSymbol = listSymbol.TypeArguments[0];
                        if (!itemTypeSymbol.IsSimpleType())
                        {
                            continue;
                        }

                        // Splitter
                        var splitter = Extensions.CharToString(arrayData?.GetValue <char?>("Splitter") ?? ',');

                        var listType = itemTypeSymbol.Name;
                        if (listType.Equals("String"))
                        {
                            valuePart = $@"StringUtils.AsEnumerable(dic.GetExact<string?>(""{dataFieldName}""), '{splitter}').ToList()";
                        }
                        else
                        {
                            valuePart = $@"StringUtils.AsEnumerable<{listType}>(dic.GetExact<string?>(""{dataFieldName}""), '{splitter}').ToList()";
                        }
                    }
                    else
                    {
                        continue;
                    }

                    if (isPositionalRecord)
                    {
                        body.Add($@"{fieldName}: {valuePart}");
                    }
                    else
                    {
                        body.Add($@"{fieldName} = {valuePart}");
                    }
                }
            }

            // Limitation: When inheritanted, please keep the same style
            // Define constructor for Positional Record
            if (isPositionalRecord)
            {
                return("(" + string.Join(",\n", body) + ")");
            }

            return("{\n" + string.Join(",\n", body) + "\n}");
        }
コード例 #6
0
        public void Execute(GeneratorExecutionContext context)
        {
            var syntaxXml = context.AdditionalFiles.SingleOrDefault(a => Path.GetFileName(a.Path) == "Syntax.xml");

            if (syntaxXml == null)
            {
                context.ReportDiagnostic(Diagnostic.Create(s_MissingSyntaxXml, location: null));
                return;
            }

            var syntaxXmlText = syntaxXml.GetText();

            if (syntaxXmlText == null)
            {
                context.ReportDiagnostic(Diagnostic.Create(s_UnableToReadSyntaxXml, location: null));
                return;
            }

            Tree tree;
            var  reader = XmlReader.Create(new SourceTextReader(syntaxXmlText), new XmlReaderSettings {
                DtdProcessing = DtdProcessing.Prohibit
            });

            try
            {
                var serializer = new XmlSerializer(typeof(Tree));
                tree = (Tree)serializer.Deserialize(reader);
            }
            catch (InvalidOperationException ex) when(ex.InnerException is XmlException)
            {
                var xmlException = (XmlException)ex.InnerException;

                var line     = syntaxXmlText.Lines[xmlException.LineNumber - 1]; // LineNumber is one-based.
                int offset   = xmlException.LinePosition - 1;                    // LinePosition is one-based
                var position = line.Start + offset;
                var span     = new TextSpan(position, 0);
                var lineSpan = syntaxXmlText.Lines.GetLinePositionSpan(span);

                context.ReportDiagnostic(
                    Diagnostic.Create(
                        s_SyntaxXmlError,
                        location: Location.Create(syntaxXml.Path, span, lineSpan),
                        xmlException.Message));

                return;
            }

            TreeFlattening.FlattenChildren(tree);

            AddResult(writer => SourceWriter.WriteMain(writer, tree, context.CancellationToken), "Syntax.xml.Main.Generated.cs");
            AddResult(writer => SourceWriter.WriteInternal(writer, tree, context.CancellationToken), "Syntax.xml.Internal.Generated.cs");
            AddResult(writer => SourceWriter.WriteSyntax(writer, tree, context.CancellationToken), "Syntax.xml.Syntax.Generated.cs");

            void AddResult(Action <TextWriter> writeFunction, string hintName)
            {
                // Write out the contents to a StringBuilder to avoid creating a single large string
                // in memory
                var stringBuilder = new StringBuilder();

                using (var textWriter = new StringWriter(stringBuilder))
                {
                    writeFunction(textWriter);
                }

                // And create a SourceText from the StringBuilder, once again avoiding allocating a single massive string
                context.AddSource(hintName, SourceText.From(new StringBuilderReader(stringBuilder), stringBuilder.Length, encoding: Encoding.UTF8));
            }
        }
コード例 #7
0
 public InpcClassGenerator CreateGenerator(ClassToImplement target, GeneratorExecutionContext context) =>
コード例 #8
0
 public TypeDeclarationContext(GeneratorExecutionContext ctx, TypeDeclarationSyntax syntax)
 {
     Syntax        = syntax;
     SemanticModel = ctx.Compilation.GetSemanticModel(syntax.SyntaxTree);
 }
コード例 #9
0
 public void Execute(GeneratorExecutionContext context)
 {
     InjectCloneableAttributes(context);
     GenerateCloneMethods(context);
 }
コード例 #10
0
 public void Execute(GeneratorExecutionContext context)
 {
     Tracker = (AttributeTracker)context.SyntaxReceiver;
     Members = Tracker.GetMembers(context.Compilation);
 }
コード例 #11
0
 private static void InjectCloneableAttributes(GeneratorExecutionContext context)
 {
     context.AddSource(CloneableAttributeString, SourceText.From(cloneableAttributeText, Encoding.UTF8));
     context.AddSource(CloneAttributeString, SourceText.From(clonePropertyAttributeText, Encoding.UTF8));
     context.AddSource(IgnoreCloneAttributeString, SourceText.From(ignoreClonePropertyAttributeText, Encoding.UTF8));
 }
コード例 #12
0
 public void Execute(GeneratorExecutionContext context) => throw new NotImplementedException();
コード例 #13
0
 public GeneratorContext(GeneratorExecutionContext generatorExecutionContext)
 {
     _syntaxCollector            = (SyntaxCollector)generatorExecutionContext.SyntaxReceiver !;
     _compilationAnalysisContext = null;
     _generatorExecutionContext  = generatorExecutionContext;
 }
コード例 #14
0
 private IReadOnlyList <string> GetGraphQLConfigFiles(
     GeneratorExecutionContext context) =>
 context.AdditionalFiles
 .Select(t => t.Path)
 .Where(t => IOPath.GetFileName(t).EqualsOrdinal(".graphqlrc.json"))
 .ToList();
コード例 #15
0
        public void Execute(GeneratorExecutionContext context)
        {
            string ns        = context.Compilation.AssemblyName ?? context.Compilation.ToString();
            string className = $"PropertySync";
            string fullName  = $"{ns}.{className}";

            Class stubClass = new Class(className).SetStatic(true)
                              .SetNamespace(ns)
                              .WithAccessibility(Accessibility.Internal)
                              .WithMethod(SyncMethod.Stub())
                              .WithMethod(SyncMethodAll.Stub())
                              .WithMethod(SyncToDictMethod.Stub())
                              .WithMethod(SyncFromDictMethod.Stub());

            Compilation      compilation   = GetStubCompilation(context, stubClass);
            INamedTypeSymbol?stubClassType = compilation.GetTypeByMetadataName(fullName);

            IEnumerable <(ITypeSymbol, ITypeSymbol)> calls = GetStubCalls(compilation, stubClassType);

            Class generatedClass = new Class(className).SetStatic(true)
                                   .SetNamespace(ns)
                                   .WithAccessibility(Accessibility.Internal);

            var generatedToTypes         = new HashSet <ITypeSymbol>(SymbolEqualityComparer.Default);
            var generatedFromTypes       = new HashSet <ITypeSymbol>(SymbolEqualityComparer.Default);
            var generatedSyncSrcTypes    = new HashSet <ITypeSymbol>(SymbolEqualityComparer.Default);
            var generatedSyncTargetTypes = new HashSet <ITypeSymbol>(SymbolEqualityComparer.Default);

            if (calls.Any())
            {
                foreach ((ITypeSymbol t1, ITypeSymbol t2) in calls)
                {
                    if (t1 is null || t2 is null)
                    {
                        continue;
                    }

                    if (t1.ToString() == CommonTypes.StringDict)
                    {
                        if (generatedFromTypes.Contains(t2))
                        {
                            continue;
                        }

                        generatedClass = generatedClass.WithMethod(new SyncFromDictMethod(t2).Build());
                        generatedFromTypes.Add(t2);
                    }
                    else if (t2.ToString() == CommonTypes.StringDict)
                    {
                        if (generatedToTypes.Contains(t1))
                        {
                            continue;
                        }

                        generatedClass = generatedClass.WithMethod(new SyncToDictMethod(t1).Build());
                        generatedToTypes.Add(t1);
                    }
                    else
                    {
                        if (generatedSyncSrcTypes.Contains(t1) && generatedSyncTargetTypes.Contains(t2))
                        {
                            continue;
                        }

                        generatedClass = generatedClass.WithMethod(new SyncMethod(t1, t2).Build()).WithMethod(new SyncMethodAll(t1, t2).Build());
                        generatedSyncSrcTypes.Add(t1);
                        generatedSyncTargetTypes.Add(t2);
                    }
                }

                string str = ClassWriter.Write(generatedClass);

                context.AddSource(className, SourceText.From(str, Encoding.UTF8));
            }
            else
            {
                context.AddSource(stubClass.ClassName, SourceText.From(ClassWriter.Write(stubClass), Encoding.UTF8));
            }
        }
コード例 #16
0
        public void Execute(GeneratorExecutionContext context)
        {
            var jsonAttributeSource = SourceText.From(GeneratorAttributesText, Encoding.UTF8);

            context.AddSource("JsonDiscriminatorAttributes.g.cs", jsonAttributeSource);

            // Retreive the populated receiver
            if (context.SyntaxReceiver is not JsonDiscriminatorReceiver receiver ||
                receiver.Candidates.Count == 0)
            {
                return;
            }

            // Retrieve CSharp compilation from context
            if (context.Compilation is not CSharpCompilation prevCompilation)
            {
                return;
            }

            // Add new attribute to compilation
            var options     = prevCompilation.SyntaxTrees[0].Options as CSharpParseOptions;
            var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(jsonAttributeSource, options));

            // Retrieve enum type
            var enumType = compilation.GetTypeByMetadataName(typeof(System.Enum).FullName);

            // Define 'fake' json converter attribute
            {
                var sb = new IndentedStringBuilder()
                         .AppendLine("#nullable enable")
                         .AppendLine("using System;")
                         .AppendLine("using System.Runtime.Serialization;")
                         .AppendLine("using System.Text.Json;")
                         .AppendLine("using System.Text.Json.Serialization;")
                         .AppendLine()
                ;

                using (sb.AppendLine($"namespace Wivuu.Polymorphism").Indent('{'))
                {
                    using (sb.AppendLine("internal abstract class JsonInheritanceConverter<T> : JsonConverter<T>").Indent('{'))
                    {
                        sb.AppendLine("public abstract string DiscriminatorName { get; }")
                        .AppendLine("public override abstract T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options);")
                        .AppendLine("public override abstract void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options);")
                        ;
                    }
                }

                context.AddSource($"JsonInheritanceConverter.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
            }

            // Create JsonConverters
            foreach (var(attr, node, symbol) in receiver.GetDiscriminators(compilation))
            {
                if (GetParentDeclaration(node) is not TypeDeclarationSyntax parentTypeNode)
                {
                    continue;
                }

                if (symbol.ContainingType is not INamedTypeSymbol parentSymbol)
                {
                    continue;
                }

                // Ensure that parent type is not concrete so that we do not cause stack overflow on serialize
                if (!parentTypeNode.Modifiers.Any(SyntaxKind.AbstractKeyword) &&
                    parentSymbol.TypeKind != TypeKind.Interface)
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(DiagTypeNotBeConcrete, parentSymbol.Locations[0]));
                    continue;
                }

                // Ensure that parent type is partial so we can attach the JsonConverter attribute
                if (!parentTypeNode.Modifiers.Any(SyntaxKind.PartialKeyword))
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(DiagNotPartial, parentSymbol.Locations[0], parentSymbol.Name));
                    continue;
                }

                // Ensure that the discriminator is an enum
                var discriminatorType =
                    symbol is IParameterSymbol param ? param.Type as INamedTypeSymbol :
                    symbol is IPropertySymbol prop   ? prop.Type as INamedTypeSymbol  :
                    default;

                if (discriminatorType is null ||
                    discriminatorType.BaseType?.Equals(enumType, SymbolEqualityComparer.Default) is not true)
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(DiagNotEnum, symbol.Locations[0], discriminatorType?.Name ?? symbol.Name));
                    continue;
                }

                // Retrieve fallback attributes for the parent type
                var fallbacks = new List <(CSharpSyntaxNode, ISymbol)>(receiver.GetFallbacks(compilation, parentSymbol));

                if (fallbacks.Count > 1)
                {
                    foreach (var(_, fbSymbol) in fallbacks)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(DiagOnlyOneFallback, fbSymbol.Locations[0]));
                    }
                    continue;
                }

                // Get all possible enum values and corresponding types
                var classMembers = new List <(string, INamedTypeSymbol, int)>(
                    GetCorrespondingTypes(context, compilation, parentSymbol, discriminatorType, fallbacks.Count == 1));

                classMembers.Sort(new SpecificityComparer());

                var sb = new IndentedStringBuilder();

                sb.AppendLine("#nullable enable")
                .AppendLine("using System;")
                .AppendLine("using System.Runtime.Serialization;")
                .AppendLine("using System.Text.Json;")
                .AppendLine("using System.Text.Json.Serialization;")
                .AppendLine()
                ;

                var ns = symbol.ContainingType.ContainingNamespace;

                using (sb.AppendLine($"namespace {ns.ToDisplayString()}").Indent('{'))
                {
                    // Append known types
                    foreach (var(_, className, _) in classMembers)
                    {
                        sb.AppendLine($"[KnownType(typeof({className.Name}))]");
                    }

                    // Attribute adding class
                    sb.AppendLine($"[JsonConverter(typeof({parentSymbol.Name}Converter))]");
                    using (sb.AppendLine($"{parentTypeNode.Modifiers} {parentTypeNode.Keyword.Text} {parentSymbol.Name}").Indent('{'))
                    {
                        // Add static array to house all types
                        using (sb.AppendLine($"private static readonly Type[] _allTypes = ").Indent('{', endCh: "};"))
                        {
                            // Iterate through each member case
                            foreach (var(_, type, _) in classMembers)
                            {
                                sb.AppendLine($"typeof({type}),");
                            }
                        }

                        // Add static method to get all types
                        sb.AppendLine($"/// <summary>")
                        .AppendLine($"/// Gets all types that are known to the <see cref=\"{parentSymbol.Name}\"/> converter.")
                        .AppendLine($"/// </summary>")
                        .AppendLine($"/// <returns>All types that are known to the <see cref=\"{parentSymbol.Name}\"/> converter.</returns>")
                        .AppendLine("#pragma warning disable CS0109");
                        using (sb.AppendLine($"public static new Type[] GetAllTypes()").Indent('{'))
                        {
                            sb.AppendLine("return _allTypes;");
                        }
                        sb.AppendLine("#pragma warning restore CS0109");

                        // Add static method to get type from discriminator
                        using (sb.AppendLine($"public static Type? GetType({discriminatorType} kind)").Indent('{'))
                        {
                            using (sb.AppendLine($"return kind switch").Indent('{', endCh: "};"))
                            {
                                // Iterate through each member case
                                foreach (var(member, type, _) in classMembers)
                                {
                                    sb.AppendLine($"{discriminatorType}.{member} => typeof({type}),");
                                }

                                if (fallbacks.Count == 1 && fallbacks[0] is var(_, fbSymbol))
                                {
                                    sb.AppendLine($"_ => typeof({fbSymbol.Name})");
                                }
                                else
                                {
                                    sb.AppendLine("_ => default");
                                }
                            }
                        }
                    }

                    // Converter class
                    using (sb.AppendLine($"internal class {parentSymbol.Name}Converter : Wivuu.Polymorphism.JsonInheritanceConverter<{parentSymbol.Name}>").Indent('{'))
                    {
                        var renderedName = attr?.ConstructorArguments.Length is > 0
                            ? attr.ConstructorArguments[0].Value?.ToString()
                            : null;

                        // DiscriminatorName property
                        sb.AppendLine($"/// <summary>")
                        .AppendLine($"/// Gets the name of the discriminator property.")
                        .AppendLine($"/// </summary>")
                        .AppendLine($"public override string DiscriminatorName => \"{renderedName ?? symbol.MetadataName}\";")
                        .AppendLine()
                        ;

                        // Read Method
                        using (sb.AppendLine($"public override {parentSymbol.Name}? Read").Indent('('))
                            sb.AppendLine("ref Utf8JsonReader reader,")
                            .AppendLine("Type typeToConvert,")
                            .AppendLine("JsonSerializerOptions options")
                            ;

                        using (sb.Indent('{'))
                        {
                            // TODO: Determine better way to find in case insensitive way
                            var ident      = symbol.MetadataName;
                            var camelIdent = string.Concat(char.ToLowerInvariant(ident[0]), ident.Substring(1));

                            sb.AppendLine("var deserializedObj = JsonElement.ParseValue(ref reader);")
                            .AppendLine("var discriminator   = options.PropertyNamingPolicy == JsonNamingPolicy.CamelCase")
                            .AppendLine($"    ? \"{camelIdent}\" : \"{ident}\";")
                            .AppendLine()
                            ;

                            using (sb.AppendLine("if (deserializedObj.TryGetProperty(discriminator, out var property))").Indent('{'))
                                using (sb.AppendLine($"return property.Deserialize<{discriminatorType}>(options)").Indent())
                                {
                                    using (sb.AppendLine("switch").Indent('{', endCh: "};"))
                                    {
                                        // Iterate through each member case
                                        foreach (var(member, type, _) in classMembers)
                                        {
                                            sb.AppendLine($"{discriminatorType}.{member} => deserializedObj.Deserialize<{type}>(options),")
                                            .AppendLine()
                                            ;
                                        }

                                        if (fallbacks.Count == 1 && fallbacks[0] is var(_, fbSymbol))
                                        {
                                            sb.AppendLine($"_ => deserializedObj.Deserialize<{fbSymbol.Name}>(options),")
                                            .AppendLine()
                                            ;
                                        }
                                        else
                                        {
                                            sb.AppendLine("_ => default");
                                        }
                                    }
                                }

                            sb.AppendLine("return default;");
                        }

                        sb.AppendLine();

                        // Write Method
                        using (sb.AppendLine($"public override void Write").Indent('('))
                            sb.AppendLine("Utf8JsonWriter writer,")
                            .AppendLine($"{parentSymbol.Name} value,")
                            .AppendLine("JsonSerializerOptions options")
                            ;

                        using (sb.Indent('{'))
                            using (sb.AppendLine("switch (value)").Indent('{'))
                            {
                                var i = 0;

                                // Iterate through each member case
                                foreach (var(_, className, _) in classMembers)
                                {
                                    ++i;

                                    using (sb.AppendLine($"case {className.Name} value{i}:").Indent())
                                        sb.AppendLine($"JsonSerializer.Serialize(writer, value{i}, options);")
                                        .AppendLine("break;")
                                        ;

                                    sb.AppendLine();
                                }

                                using (sb.AppendLine($"default:").Indent())
                                    if (fallbacks.Count == 1 && fallbacks[0] is var(_, fbSymbol))
                                    {
                                        ++i;

                                        sb.AppendLine($"if (value is {fbSymbol.Name} value{i})").Indent('{', sb =>
                                                                                                        sb.AppendLine($"JsonSerializer.Serialize(writer, value{i}, options);")
                                                                                                        .AppendLine("break;")
                                                                                                        )
                                        .AppendLine("else")
                                        .AppendLine($"    throw new JsonException($\"{{value.{symbol.MetadataName}}} is not a supported value\");");
                                        ;
                                    }
                                    else
                                    {
                                        sb.AppendLine($"throw new JsonException($\"{{value.{symbol.MetadataName}}} is not a supported value\");");
                                    }
                            }
                    }
                }

                // Add source
                context.AddSource($"{parentSymbol.Name}Converter.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
            }
        }
コード例 #17
0
        private static void GenerateExtensions(GeneratorExecutionContext context)
        {
            const string mpWriterExtensions = @"
using System.Numerics;
using MessagePack;

namespace ToolGeneratedExtensions
{
    internal static class MessagePackExtensions
    {
        public static void Write(this ref MessagePackWriter writer, Vector2 v)
        {
            writer.WriteArrayHeader(2);
            writer.Write(v.X);
            writer.Write(v.Y);
        }

        public static Vector2 ReadVector2(this ref MessagePackReader reader)
        {
            reader.ReadArrayHeader();
            return new Vector2(reader.ReadSingle(), reader.ReadSingle());
        }

        public static void Write(this ref MessagePackWriter writer, in Vector3 v)
        {
            writer.WriteArrayHeader(3);
            writer.Write(v.X);
            writer.Write(v.Y);
            writer.Write(v.Z);
        }

        public static Vector3 ReadVector3(this ref MessagePackReader reader)
        {
            reader.ReadArrayHeader();
            return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
        }

        public static void Write(this ref MessagePackWriter writer, in Vector4 v)
        {
            writer.WriteArrayHeader(4);
            writer.Write(v.X);
            writer.Write(v.Y);
            writer.Write(v.Z);
            writer.Write(v.W);
        }

        public static Vector4 ReadVector4(this ref MessagePackReader reader)
        {
            reader.ReadArrayHeader();
            return new Vector4(
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle()
            );
        }

        public static void Write(this ref MessagePackWriter writer, in Matrix4x4 m)
        {
            writer.WriteArrayHeader(16);
            writer.Write(m.M11);
            writer.Write(m.M12);
            writer.Write(m.M13);
            writer.Write(m.M14);
            writer.Write(m.M21);
            writer.Write(m.M22);
            writer.Write(m.M23);
            writer.Write(m.M24);
            writer.Write(m.M31);
            writer.Write(m.M32);
            writer.Write(m.M33);
            writer.Write(m.M34);
            writer.Write(m.M41);
            writer.Write(m.M42);
            writer.Write(m.M43);
            writer.Write(m.M44);
        }

        public static Matrix4x4 ReadMatrix4x4(this ref MessagePackReader reader)
        {
            reader.ReadArrayHeader();
            return new Matrix4x4(
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle(),
                reader.ReadSingle()
            );
        }
    }
}";

            context.AddSource("MessagePackExtensions.cs", SourceText.From(mpWriterExtensions, Encoding.UTF8));
        }
コード例 #18
0
        private void GenerateCode(GeneratorExecutionContext context, TypeDeclarationSyntax tds, Type attributeType)
        {
            // Field symbol
            var symbol = context.ParseSyntaxNode <INamedTypeSymbol>(tds);

            if (symbol == null || context.CancellationToken.IsCancellationRequested)
            {
                return;
            }

            // Attribute data
            var attributeData = symbol.GetAttributeData(attributeType.FullName);

            // Snake case
            var snakeCase = attributeData?.GetValue <bool>(nameof(AutoToParametersAttribute.SnakeCase));

            // Name space and class name
            var(ns, className) = (symbol.ContainingNamespace.ToDisplayString(), symbol.Name);

            // Keyword
            var keyword = tds.Keyword.ToString();

            // Is Public
            var isPublic = tds.HasToken(SyntaxKind.PublicKeyword);

            // Name
            var name = tds.Identifier.ToString();

            // Inheritance
            var externals = new List <string>();

            // Body
            var body = GenerateBody(context, tds, snakeCase.GetValueOrDefault(), externals, ns);

            if (context.CancellationToken.IsCancellationRequested)
            {
                return;
            }

            externals.Add($"com.etsoo.Utils.Serialization.IDictionaryParser<{name}>");

            // Source code
            var source = $@"#nullable enable
                using com.etsoo.Utils.String;
                using System;
                using System.Collections.Generic;
                using System.Linq;

                namespace {ns}
                {{
                    {(isPublic ? "public" : "internal")} partial {keyword} {className} : {string.Join(", ", externals)}
                    {{
                        public static {name} Create(StringKeyDictionaryObject dic)
                        {{
                            return new {name} {body};
                        }}
                    }}
                }}
            ";

            context.AddSource($"{ns}.{className}.Dictionary.Generated.cs", SourceText.From(source, Encoding.UTF8));
        }
コード例 #19
0
 public virtual void Execute(GeneratorExecutionContext context)
 {
     context.AddSource("EmptyGeneratedFile", string.Empty);
 }
コード例 #20
0
 public void Execute(GeneratorExecutionContext context)
 {
     context.AddSource(this._hintName, SourceText.From(_content, Encoding.UTF8));
 }
コード例 #21
0
        public void Execute(GeneratorExecutionContext context)
        {
//#if DEBUG
//            if (!Debugger.IsAttached)
//                Debugger.Launch();
//#endif

            ICollection <string> typeNames = context.Compilation.Assembly.TypeNames;

            HashSet <string> topicNames = new HashSet <string>(StringComparer.Ordinal);

            foreach (string typeName in typeNames)
            {
                INamedTypeSymbol p = context.Compilation.GetSymbolsWithName(typeName).FirstOrDefault() as INamedTypeSymbol;
                if (p == null)
                {
                    continue;
                }

                if (!p.AllInterfaces.Any(x => x.Name == "IHassDiscoveryDocument"))
                {
                    continue;
                }

                List <ISymbol> props = p.GetMembers()
                                       .Where(s => s.Name.EndsWith("Topic") && s.Kind == SymbolKind.Property)
                                       .ToList();

                foreach (ISymbol symbol in props)
                {
                    string name = symbol.Name.Replace("Topic", "");
                    topicNames.Add(name);
                }
            }

            // Remove some names
            topicNames.Remove("");
            topicNames.Remove("Publish");

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("using System.Runtime.Serialization;");
            sb.AppendLine("");
            sb.AppendLine("namespace MBW.HassMQTT.DiscoveryModels.Enum");
            sb.AppendLine("{");
            sb.AppendLine("  public enum HassTopicKind");
            sb.AppendLine("  {");

            foreach (string topicName in topicNames.OrderBy(s => s))
            {
                string value = Regex.Replace(topicName, "[A-Z]", match =>
                {
                    if (match.Index == 0)
                    {
                        return(match.Value.ToLower());
                    }
                    return("_" + match.Value.ToLower());
                });

                sb.AppendLine($"    [EnumMember(Value = \"{value}\")]");
                sb.AppendLine($"    {topicName},");
            }

            sb.AppendLine("  }");
            sb.AppendLine("}");

            context.AddSource("HassTopicKind_generated.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
        }