From 30648d51ba0bd0881bb581cf5c016aae90a8e2d7 Mon Sep 17 00:00:00 2001 From: hadashiA Date: Sun, 10 Dec 2023 17:13:28 +0900 Subject: [PATCH 1/5] Add IncrementalSourceGenerator (for microsoft.codeanalysis.csharp 4.1.0) --- VYaml.SourceGenerator.Roslyn3/CodeWriter.cs | 2 +- .../ReferenceSymbols.cs | 2 +- .../SyntaxContextReceiver.cs | 3 +- VYaml.SourceGenerator/CodeWriter.cs | 121 +++ .../DiagnosticDescriptors.cs | 128 ++++ VYaml.SourceGenerator/KeyNameMutator.cs | 75 ++ VYaml.SourceGenerator/MemberMeta.cs | 81 ++ .../Properties/launchSettings.json | 9 + VYaml.SourceGenerator/ReferenceSymbols.cs | 30 + .../Shims/CSharpSyntaxHelper.cs | 127 ++++ .../Shims/CompilationExtensions.cs | 189 +++++ VYaml.SourceGenerator/Shims/GlobalAliases.cs | 76 ++ VYaml.SourceGenerator/Shims/ISyntaxHelper.cs | 68 ++ .../Shims/ImmutableArrayValueComparer.cs | 31 + ...ueProvider_ForAttributeWithMetadataName.cs | 203 ++++++ ...alueProvider_ForAttributeWithSimpleName.cs | 455 ++++++++++++ .../Shims/ValueListHelper.cs | 213 ++++++ VYaml.SourceGenerator/SymbolExtensions.cs | 96 +++ VYaml.SourceGenerator/TypeMeta.cs | 117 +++ .../VYaml.SourceGenerator.csproj | 26 + .../VYamlIncrementalSourceGenerator.cs | 689 ++++++++++++++++++ .../Serialization/GeneratorDiagnosticsTest.cs | 48 -- VYaml.Tests/VYaml.Tests.csproj | 9 +- VYaml.Unity/Assets/VYaml/PerformanceTest.meta | 8 + .../VYaml/PerformanceTest/PerformanceTest.cs | 119 +++ .../PerformanceTest/PerformanceTest.cs.meta | 11 + .../VYaml/PerformanceTest/SampleEnvoy.cs | 120 +++ .../VYaml/PerformanceTest/SampleEnvoy.cs.meta | 3 + .../VYaml.PerformanceTest.asmdef | 21 + .../VYaml.PerformanceTest.asmdef.meta | 7 + .../VYaml/PerformanceTest/YamlDotNet.dll | Bin 0 -> 235520 bytes .../VYaml/PerformanceTest/YamlDotNet.dll.meta | 33 + .../Runtime/VYaml.SourceGenerator.Roslyn3.dll | Bin 48128 -> 48128 bytes .../Tests/Emitter/Utf8YamlEmitterTest.cs | 1 + .../Assets/VYaml/Tests/Parser/SpecTest.cs | 1 - .../Serialization/GeneratorDiagnosticsTest.cs | 59 +- .../ProjectSettings/ProjectSettings.asset | 95 ++- VYaml.sln | 6 + 38 files changed, 3168 insertions(+), 114 deletions(-) create mode 100644 VYaml.SourceGenerator/CodeWriter.cs create mode 100644 VYaml.SourceGenerator/DiagnosticDescriptors.cs create mode 100644 VYaml.SourceGenerator/KeyNameMutator.cs create mode 100644 VYaml.SourceGenerator/MemberMeta.cs create mode 100644 VYaml.SourceGenerator/Properties/launchSettings.json create mode 100644 VYaml.SourceGenerator/ReferenceSymbols.cs create mode 100644 VYaml.SourceGenerator/Shims/CSharpSyntaxHelper.cs create mode 100644 VYaml.SourceGenerator/Shims/CompilationExtensions.cs create mode 100644 VYaml.SourceGenerator/Shims/GlobalAliases.cs create mode 100644 VYaml.SourceGenerator/Shims/ISyntaxHelper.cs create mode 100644 VYaml.SourceGenerator/Shims/ImmutableArrayValueComparer.cs create mode 100644 VYaml.SourceGenerator/Shims/SyntaxValueProvider_ForAttributeWithMetadataName.cs create mode 100644 VYaml.SourceGenerator/Shims/SyntaxValueProvider_ForAttributeWithSimpleName.cs create mode 100644 VYaml.SourceGenerator/Shims/ValueListHelper.cs create mode 100644 VYaml.SourceGenerator/SymbolExtensions.cs create mode 100644 VYaml.SourceGenerator/TypeMeta.cs create mode 100644 VYaml.SourceGenerator/VYaml.SourceGenerator.csproj create mode 100644 VYaml.SourceGenerator/VYamlIncrementalSourceGenerator.cs delete mode 100644 VYaml.Tests/Serialization/GeneratorDiagnosticsTest.cs create mode 100644 VYaml.Unity/Assets/VYaml/PerformanceTest.meta create mode 100644 VYaml.Unity/Assets/VYaml/PerformanceTest/PerformanceTest.cs create mode 100644 VYaml.Unity/Assets/VYaml/PerformanceTest/PerformanceTest.cs.meta create mode 100644 VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs create mode 100644 VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs.meta create mode 100644 VYaml.Unity/Assets/VYaml/PerformanceTest/VYaml.PerformanceTest.asmdef create mode 100644 VYaml.Unity/Assets/VYaml/PerformanceTest/VYaml.PerformanceTest.asmdef.meta create mode 100644 VYaml.Unity/Assets/VYaml/PerformanceTest/YamlDotNet.dll create mode 100644 VYaml.Unity/Assets/VYaml/PerformanceTest/YamlDotNet.dll.meta diff --git a/VYaml.SourceGenerator.Roslyn3/CodeWriter.cs b/VYaml.SourceGenerator.Roslyn3/CodeWriter.cs index e51d980..254d910 100644 --- a/VYaml.SourceGenerator.Roslyn3/CodeWriter.cs +++ b/VYaml.SourceGenerator.Roslyn3/CodeWriter.cs @@ -2,7 +2,7 @@ namespace VYaml.SourceGenerator; -public class CodeWriter +class CodeWriter { readonly struct IndentScope : IDisposable { diff --git a/VYaml.SourceGenerator.Roslyn3/ReferenceSymbols.cs b/VYaml.SourceGenerator.Roslyn3/ReferenceSymbols.cs index 94d0713..df78f4c 100644 --- a/VYaml.SourceGenerator.Roslyn3/ReferenceSymbols.cs +++ b/VYaml.SourceGenerator.Roslyn3/ReferenceSymbols.cs @@ -2,7 +2,7 @@ namespace VYaml.SourceGenerator; -public class ReferenceSymbols +class ReferenceSymbols { public static ReferenceSymbols? Create(Compilation compilation) { diff --git a/VYaml.SourceGenerator.Roslyn3/SyntaxContextReceiver.cs b/VYaml.SourceGenerator.Roslyn3/SyntaxContextReceiver.cs index 6d621d2..ec24d14 100644 --- a/VYaml.SourceGenerator.Roslyn3/SyntaxContextReceiver.cs +++ b/VYaml.SourceGenerator.Roslyn3/SyntaxContextReceiver.cs @@ -35,6 +35,5 @@ or RecordDeclarationSyntax classDeclarations.Add(typeSyntax); } } - } - } + } } } diff --git a/VYaml.SourceGenerator/CodeWriter.cs b/VYaml.SourceGenerator/CodeWriter.cs new file mode 100644 index 0000000..564adf3 --- /dev/null +++ b/VYaml.SourceGenerator/CodeWriter.cs @@ -0,0 +1,121 @@ +using System; +using System.Text; + +namespace VYaml.SourceGenerator; + +class CodeWriter +{ + readonly struct IndentScope : IDisposable + { + readonly CodeWriter source; + + public IndentScope(CodeWriter source, string? startLine = null) + { + this.source = source; + source.AppendLine(startLine); + source.IncreaseIndent(); + } + + public void Dispose() + { + source.DecreaseIndent(); + } + } + + readonly struct BlockScope : IDisposable + { + readonly CodeWriter source; + + public BlockScope(CodeWriter source, string? startLine = null) + { + this.source = source; + source.AppendLine(startLine); + source.BeginBlock(); + } + + public void Dispose() + { + source.EndBlock(); + } + } + + readonly StringBuilder buffer = new(); + int indentLevel; + + public void Append(string value, bool indent = true) + { + if (indent) + { + buffer.Append($"{new string(' ', indentLevel * 4)} {value}"); + } + else + { + buffer.Append(value); + } + } + + public void AppendLine(string? value = null, bool indent = true) + { + if (string.IsNullOrEmpty(value)) + { + buffer.AppendLine(); + } + else if (indent) + { + buffer.AppendLine($"{new string(' ', indentLevel * 4)} {value}"); + } + else + { + buffer.AppendLine(value); + } + } + + public void AppendByteArrayString(byte[] bytes) + { + buffer.Append("{ "); + var first = true; + foreach (var x in bytes) + { + if (!first) + { + buffer.Append(", "); + } + buffer.Append(x); + first = false; + } + buffer.Append(" }"); + } + + public override string ToString() => buffer.ToString(); + + public IDisposable BeginIndentScope(string? startLine = null) => new IndentScope(this, startLine); + public IDisposable BeginBlockScope(string? startLine = null) => new BlockScope(this, startLine); + + public void IncreaseIndent() + { + indentLevel++; + } + + public void DecreaseIndent() + { + if (indentLevel > 0) + indentLevel--; + } + + public void BeginBlock() + { + AppendLine("{"); + IncreaseIndent(); + } + + public void EndBlock() + { + DecreaseIndent(); + AppendLine("}"); + } + + public void Clear() + { + buffer.Clear(); + } +} diff --git a/VYaml.SourceGenerator/DiagnosticDescriptors.cs b/VYaml.SourceGenerator/DiagnosticDescriptors.cs new file mode 100644 index 0000000..b2c15f1 --- /dev/null +++ b/VYaml.SourceGenerator/DiagnosticDescriptors.cs @@ -0,0 +1,128 @@ +using Microsoft.CodeAnalysis; + +namespace VYaml.SourceGenerator; + +static class DiagnosticDescriptors +{ + const string Category = "VYaml.SourceGenerator"; + + public static readonly DiagnosticDescriptor UnexpectedErrorDescriptor = new( + id: "VYAML001", + title: "Unexpected error during source code generation", + messageFormat: "Unexpected error occurred during source code code generation: {0}", + category: "Usage", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor MustBePartial = new( + id: "VYAML002", + title: "VYaml serializable type declaration must be partial", + messageFormat: "The VYaml serializable type declaration '{0}' must be partial", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor NestedNotAllow = new( + id: "VYAML003", + title: "VYaml serializable type must not be nested type", + messageFormat: "The VYaml serializable object '{0}' must be not nested type", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor YamlMemberPropertyMustHaveSetter = new( + id: "VYAML004", + title: "A yaml serializable property with must have setter.", + messageFormat: "The VYaml serializable object '{0}' property '{1}' must have setter.", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor YamlMemberFieldCannotBeReadonly = new( + id: "VYAML005", + title: "A yaml serializable field cannot be readonly", + messageFormat: "The VYaml serializable object '{0}' field '{1}' cannot be readonly.", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor AbstractMustUnion = new( + id: "VYAML006", + title: "abstract/interface type of `[YamlObject]` must annotate with Union", + messageFormat: "abstract/interface type of `[YamlObject]` '{0}' must annotate with Union", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor ConcreteTypeCantBeUnion = new( + id: "VYAML007", + title: "Concrete type can't be union", + messageFormat: "The object that has `[YamlObject]` '{0}' can be Union, only allow abstract or interface", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor UnionTagDuplicate = new( + id: "VYAML008", + title: "Union tag is duplicate", + messageFormat: "The object that has `[YamlObject]` '{0}' union tag value is duplicate", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor UnionMemberTypeNotImplementBaseType = new( + id: "VYAML009", + title: "Union member not implement union interface", + messageFormat: "The object '{0}' union member '{1}' not implment union interface", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor UnionMemberTypeNotDerivedBaseType = new( + id: "VYAML010", + title: "Union member not dervided union base type", + messageFormat: "The object '{0}' union member '{1}' not derived union type", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor UnionMemberNotAllowStruct = new( + id: "VYAML011", + title: "Union member can't be struct", + messageFormat: "The object '{0}' union member '{1}' can't be member, not allows struct", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor UnionMemberMustBeYamlObject = new( + id: "VYAML012", + title: "Union member must be YamlObject", + messageFormat: "The object '{0}' union member '{1}' must be [YamlObject]", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor MultipleConstructorAttribute = new( + id: "VYAML013", + title: "[YamlConstructor] exists in multiple constructors", + messageFormat: "Mupltiple [YamlConstructor] exists in '{0}' but allows only single ctor", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor MultipleConstructorWithoutAttribute = new( + id: "VYAML014", + title: "Require [YamlConstructor] when exists multiple constructors", + messageFormat: "The Yaml object '{0}' must annotate with [YamlConstructor] when exists multiple constructors", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor ConstructorHasNoMatchedParameter = new( + id: "VYAML0015", + title: "VYaml's constructor has no matched parameter", + messageFormat: "The VYaml object '{0}' constructor's parameter '{1}' must match a serialized member name(case-insensitive)", + category: Category, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); +} diff --git a/VYaml.SourceGenerator/KeyNameMutator.cs b/VYaml.SourceGenerator/KeyNameMutator.cs new file mode 100644 index 0000000..5bebf62 --- /dev/null +++ b/VYaml.SourceGenerator/KeyNameMutator.cs @@ -0,0 +1,75 @@ +using System; + +namespace VYaml.SourceGenerator; + +enum NamingConvention +{ + LowerCamelCase, + UpperCamelCase, + SnakeCase, + KebabCase, +} + +static class KeyNameMutator +{ + public static string Mutate(string s, NamingConvention namingConvention) + { + return namingConvention switch + { + NamingConvention.LowerCamelCase => ToLowerCamelCase(s), + NamingConvention.UpperCamelCase => s, + NamingConvention.SnakeCase => ToSnakeCase(s), + NamingConvention.KebabCase => ToSnakeCase(s, '-'), + _ => throw new ArgumentOutOfRangeException(nameof(namingConvention), namingConvention, null) + }; + } + + public static string ToLowerCamelCase(string s) + { + var span = s.AsSpan(); + if (span.Length <= 0 || + (span.Length <= 1 && char.IsLower(span[0]))) + { + return s; + } + + Span buf = stackalloc char[span.Length]; + span.CopyTo(buf); + buf[0] = char.ToLowerInvariant(span[0]); + return buf.ToString(); + } + + public static string ToSnakeCase(string s, char separator = '_') + { + var span = s.AsSpan(); + if (span.Length <= 0) return s; + + Span buf = stackalloc char[span.Length * 2]; + var written = 0; + foreach (var ch in span) + { + if (char.IsUpper(ch)) + { + if (written == 0 || // first + char.IsUpper(span[written - 1])) // WriteIO => write_io + { + buf[written++] = char.ToLowerInvariant(ch); + } + else + { + buf[written++] = separator; + if (buf.Length <= written) + { + buf = new char[buf.Length * 2]; + } + buf[written++] = char.ToLowerInvariant(ch); + } + } + else + { + buf[written++] = ch; + } + } + return buf.Slice(0, written).ToString(); + } +} \ No newline at end of file diff --git a/VYaml.SourceGenerator/MemberMeta.cs b/VYaml.SourceGenerator/MemberMeta.cs new file mode 100644 index 0000000..f21a8e7 --- /dev/null +++ b/VYaml.SourceGenerator/MemberMeta.cs @@ -0,0 +1,81 @@ +using System; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace VYaml.SourceGenerator; + +class MemberMeta +{ + public ISymbol Symbol { get; } + public string Name { get; } + public string FullTypeName { get; } + public ITypeSymbol MemberType { get; } + public bool IsField { get; } + public bool IsProperty { get; } + public bool IsSettable { get; } + public int Order { get; } + public bool HasExplicitOrder { get; } + public bool HasKeyNameAlias { get; } + public string KeyName { get; } + + public bool IsConstructorParameter { get; set; } + public bool HasExplicitDefaultValueFromConstructor { get; set; } + public object? ExplicitDefaultValueFromConstructor { get; set; } + + public byte[] KeyNameUtf8Bytes => keyNameUtf8Bytes ??= System.Text.Encoding.UTF8.GetBytes(KeyName); + byte[]? keyNameUtf8Bytes; + + public MemberMeta(ISymbol symbol, ReferenceSymbols references, NamingConvention namingConvention, int sequentialOrder) + { + Symbol = symbol; + Name = symbol.Name; + Order = sequentialOrder; + KeyName = KeyNameMutator.Mutate(Name, namingConvention); + + var memberAttribute = symbol.GetAttribute(references.YamlMemberAttribute); + if (memberAttribute != null) + { + if (memberAttribute.ConstructorArguments.Length > 0 && + memberAttribute.ConstructorArguments[0].Value is string aliasValue) + { + HasKeyNameAlias = true; + KeyName = aliasValue; + } + + var orderProp = memberAttribute.NamedArguments.FirstOrDefault(x => x.Key == "Order"); + if (orderProp.Key != "Order" && orderProp.Value.Value is { } explicitOrder) + { + HasExplicitOrder = true; + Order = (int)explicitOrder; + } + } + + if (symbol is IFieldSymbol f) + { + IsProperty = false; + IsField = true; + IsSettable = !f.IsReadOnly; // readonly field can not set. + MemberType = f.Type; + + } + else if (symbol is IPropertySymbol p) + { + IsProperty = true; + IsField = false; + IsSettable = !p.IsReadOnly; + MemberType = p.Type; + } + else + { + throw new Exception("member is not field or property."); + } + FullTypeName = MemberType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + } + + public Location GetLocation(TypeDeclarationSyntax fallback) + { + var location = Symbol.Locations.FirstOrDefault() ?? fallback.Identifier.GetLocation(); + return location; + } +} diff --git a/VYaml.SourceGenerator/Properties/launchSettings.json b/VYaml.SourceGenerator/Properties/launchSettings.json new file mode 100644 index 0000000..9a53a5d --- /dev/null +++ b/VYaml.SourceGenerator/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "DebugRoslynSourceGenerator": { + "commandName": "DebugRoslynComponent", + "targetProject": "../VYaml.SourceGenerator.Sample/VYaml.SourceGenerator.Sample.csproj" + } + } +} \ No newline at end of file diff --git a/VYaml.SourceGenerator/ReferenceSymbols.cs b/VYaml.SourceGenerator/ReferenceSymbols.cs new file mode 100644 index 0000000..94d0713 --- /dev/null +++ b/VYaml.SourceGenerator/ReferenceSymbols.cs @@ -0,0 +1,30 @@ +using Microsoft.CodeAnalysis; + +namespace VYaml.SourceGenerator; + +public class ReferenceSymbols +{ + public static ReferenceSymbols? Create(Compilation compilation) + { + var yamlObjectAttribute = compilation.GetTypeByMetadataName("VYaml.Annotations.YamlObjectAttribute"); + if (yamlObjectAttribute is null) + return null; + + return new ReferenceSymbols + { + YamlObjectAttribute = yamlObjectAttribute, + YamlMemberAttribute = compilation.GetTypeByMetadataName("VYaml.Annotations.YamlMemberAttribute")!, + YamlIgnoreAttribute = compilation.GetTypeByMetadataName("VYaml.Annotations.YamlIgnoreAttribute")!, + YamlConstructorAttribute = compilation.GetTypeByMetadataName("VYaml.Annotations.YamlConstructorAttribute")!, + YamlObjectUnionAttribute = compilation.GetTypeByMetadataName("VYaml.Annotations.YamlObjectUnionAttribute")!, + NamingConventionEnum = compilation.GetTypeByMetadataName("VYaml.Annotations.NamingConvention")! + }; + } + + public INamedTypeSymbol YamlObjectAttribute { get; private set; } = default!; + public INamedTypeSymbol YamlMemberAttribute { get; private set; } = default!; + public INamedTypeSymbol YamlIgnoreAttribute { get; private set; } = default!; + public INamedTypeSymbol YamlConstructorAttribute { get; private set; } = default!; + public INamedTypeSymbol YamlObjectUnionAttribute { get; private set; } = default!; + public INamedTypeSymbol NamingConventionEnum { get; private set; } = default!; +} diff --git a/VYaml.SourceGenerator/Shims/CSharpSyntaxHelper.cs b/VYaml.SourceGenerator/Shims/CSharpSyntaxHelper.cs new file mode 100644 index 0000000..fb07646 --- /dev/null +++ b/VYaml.SourceGenerator/Shims/CSharpSyntaxHelper.cs @@ -0,0 +1,127 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Copied from https://github.com/dotnet/runtime/blob/1473deaa50785b956edd7d078e68c0581c1b4d95/src/libraries/Common/src/Roslyn/CSharpSyntaxHelper.cs + +using System.Collections.Generic; +using System.Diagnostics; + +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions +{ + internal sealed class CSharpSyntaxHelper : AbstractSyntaxHelper + { + public static readonly ISyntaxHelper Instance = new CSharpSyntaxHelper(); + + private CSharpSyntaxHelper() + { + } + + public override bool IsCaseSensitive + => true; + + public override bool IsValidIdentifier(string name) + => SyntaxFacts.IsValidIdentifier(name); + + public override bool IsAnyNamespaceBlock(SyntaxNode node) + => node is BaseNamespaceDeclarationSyntax; + + public override bool IsAttribute(SyntaxNode node) + => node is AttributeSyntax; + + public override SyntaxNode GetNameOfAttribute(SyntaxNode node) + => ((AttributeSyntax)node).Name; + + public override bool IsAttributeList(SyntaxNode node) + => node is AttributeListSyntax; + + public override void AddAttributeTargets(SyntaxNode node, ref ValueListBuilder targets) + { + var attributeList = (AttributeListSyntax)node; + var container = attributeList.Parent; + Debug.Assert(container != null); + + // For fields/events, the attribute applies to all the variables declared. + if (container is FieldDeclarationSyntax field) + { + foreach (var variable in field.Declaration.Variables) + targets.Append(variable); + } + else if (container is EventFieldDeclarationSyntax ev) + { + foreach (var variable in ev.Declaration.Variables) + targets.Append(variable); + } + else + { + targets.Append(container); + } + } + + public override SeparatedSyntaxList GetAttributesOfAttributeList(SyntaxNode node) + => ((AttributeListSyntax)node).Attributes; + + public override bool IsLambdaExpression(SyntaxNode node) + => node is LambdaExpressionSyntax; + + public override SyntaxToken GetUnqualifiedIdentifierOfName(SyntaxNode node) + => ((NameSyntax)node).GetUnqualifiedName().Identifier; + + public override void AddAliases(SyntaxNode node, ref ValueListBuilder<(string aliasName, string symbolName)> aliases, bool global) + { + if (node is CompilationUnitSyntax compilationUnit) + { + AddAliases(compilationUnit.Usings, ref aliases, global); + } + else if (node is BaseNamespaceDeclarationSyntax namespaceDeclaration) + { + AddAliases(namespaceDeclaration.Usings, ref aliases, global); + } + else + { + Debug.Fail("This should not be reachable. Caller already checked we had a compilation unit or namespace."); + } + } + + private static void AddAliases(SyntaxList usings, ref ValueListBuilder<(string aliasName, string symbolName)> aliases, bool global) + { + foreach (var usingDirective in usings) + { + if (usingDirective.Alias is null) + continue; + + if (global != usingDirective.GlobalKeyword.Kind() is SyntaxKind.GlobalKeyword) + continue; + + var aliasName = usingDirective.Alias.Name.Identifier.ValueText; + var symbolName = usingDirective.Name.GetUnqualifiedName().Identifier.ValueText; + aliases.Append((aliasName, symbolName)); + } + } + + public override void AddAliases(CompilationOptions compilation, ref ValueListBuilder<(string aliasName, string symbolName)> aliases) + { + // C# doesn't have global aliases at the compilation level. + return; + } + + public override bool ContainsGlobalAliases(SyntaxNode root) + { + // Global usings can only exist at the compilation-unit level, so no need to dive any deeper than that. + var compilationUnit = (CompilationUnitSyntax)root; + + foreach (var directive in compilationUnit.Usings) + { + if (directive.GlobalKeyword.IsKind(SyntaxKind.GlobalKeyword) && + directive.Alias != null) + { + return true; + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/VYaml.SourceGenerator/Shims/CompilationExtensions.cs b/VYaml.SourceGenerator/Shims/CompilationExtensions.cs new file mode 100644 index 0000000..9cc3ef8 --- /dev/null +++ b/VYaml.SourceGenerator/Shims/CompilationExtensions.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Copied from https://github.com/dotnet/runtime/blob/1473deaa50785b956edd7d078e68c0581c1b4d95/src/libraries/Common/src/Roslyn/GetBestTypeByMetadataName.cs + +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions +{ + internal static class RoslynExtensions + { + // Copied from: https://github.com/dotnet/roslyn/blob/main/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/CompilationExtensions.cs + /// + /// Gets a type by its metadata name to use for code analysis within a . This method + /// attempts to find the "best" symbol to use for code analysis, which is the symbol matching the first of the + /// following rules. + /// + /// + /// + /// If only one type with the given name is found within the compilation and its referenced assemblies, that + /// type is returned regardless of accessibility. + /// + /// + /// If the current defines the symbol, that symbol is returned. + /// + /// + /// If exactly one referenced assembly defines the symbol in a manner that makes it visible to the current + /// , that symbol is returned. + /// + /// + /// Otherwise, this method returns . + /// + /// + /// + /// The to consider for analysis. + /// The fully-qualified metadata type name to find. + /// The symbol to use for code analysis; otherwise, . + public static INamedTypeSymbol? GetBestTypeByMetadataName(this Compilation compilation, string fullyQualifiedMetadataName) + { + // Try to get the unique type with this name, ignoring accessibility + var type = compilation.GetTypeByMetadataName(fullyQualifiedMetadataName); + + // Otherwise, try to get the unique type with this name originally defined in 'compilation' + type ??= compilation.Assembly.GetTypeByMetadataName(fullyQualifiedMetadataName); + + // Otherwise, try to get the unique accessible type with this name from a reference + if (type is null) + { + foreach (var module in compilation.Assembly.Modules) + { + foreach (var referencedAssembly in module.ReferencedAssemblySymbols) + { + var currentType = referencedAssembly.GetTypeByMetadataName(fullyQualifiedMetadataName); + if (currentType is null) + continue; + + switch (currentType.GetResultantVisibility()) + { + case SymbolVisibility.Public: + case SymbolVisibility.Internal when referencedAssembly.GivesAccessTo(compilation.Assembly): + break; + + default: + continue; + } + + if (type is object) + { + // Multiple visible types with the same metadata name are present + return null; + } + + type = currentType; + } + } + } + + return type; + } + + /// + /// A thin wrapper over , + /// but taking the type itself rather than the fully-qualified metadata type name. + /// + /// The to consider for analysis. + /// The type to find. + /// + public static INamedTypeSymbol? GetBestTypeByMetadataName(this Compilation compilation, Type type) => + type.IsArray || type.FullName is null + ? throw new ArgumentException("The input type must correspond to a named type symbol.") + : GetBestTypeByMetadataName(compilation, type.FullName); + + // copied from https://github.com/dotnet/roslyn/blob/main/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs + private static SymbolVisibility GetResultantVisibility(this ISymbol symbol) + { + // Start by assuming it's visible. + SymbolVisibility visibility = SymbolVisibility.Public; + + switch (symbol.Kind) + { + case SymbolKind.Alias: + // Aliases are uber private. They're only visible in the same file that they + // were declared in. + return SymbolVisibility.Private; + + case SymbolKind.Parameter: + // Parameters are only as visible as their containing symbol + return GetResultantVisibility(symbol.ContainingSymbol); + + case SymbolKind.TypeParameter: + // Type Parameters are private. + return SymbolVisibility.Private; + } + + while (symbol != null && symbol.Kind != SymbolKind.Namespace) + { + switch (symbol.DeclaredAccessibility) + { + // If we see anything private, then the symbol is private. + case Accessibility.NotApplicable: + case Accessibility.Private: + return SymbolVisibility.Private; + + // If we see anything internal, then knock it down from public to + // internal. + case Accessibility.Internal: + case Accessibility.ProtectedAndInternal: + visibility = SymbolVisibility.Internal; + break; + + // For anything else (Public, Protected, ProtectedOrInternal), the + // symbol stays at the level we've gotten so far. + } + + symbol = symbol.ContainingSymbol; + } + + return visibility; + } + + // Copied from: https://github.com/dotnet/roslyn/blob/main/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolVisibility.cs +#pragma warning disable CA1027 // Mark enums with FlagsAttribute + private enum SymbolVisibility +#pragma warning restore CA1027 // Mark enums with FlagsAttribute + { + Public = 0, + Internal = 1, + Private = 2, + Friend = Internal, + } + + internal static bool HasAttributeSuffix(this string name, bool isCaseSensitive) + { + const string AttributeSuffix = "Attribute"; + + var comparison = isCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; + return name.Length > AttributeSuffix.Length && name.EndsWith(AttributeSuffix, comparison); + } + + public static ImmutableArray ToImmutableArray(this ReadOnlySpan span) + { + switch (span.Length) + { + case 0: return ImmutableArray.Empty; + case 1: return ImmutableArray.Create(span[0]); + case 2: return ImmutableArray.Create(span[0], span[1]); + case 3: return ImmutableArray.Create(span[0], span[1], span[2]); + case 4: return ImmutableArray.Create(span[0], span[1], span[2], span[3]); + default: + var builder = ImmutableArray.CreateBuilder(span.Length); + foreach (var item in span) + builder.Add(item); + + return builder.MoveToImmutable(); + } + } + + public static SimpleNameSyntax GetUnqualifiedName(this NameSyntax name) + => name switch + { + AliasQualifiedNameSyntax alias => alias.Name, + QualifiedNameSyntax qualified => qualified.Right, + SimpleNameSyntax simple => simple, + _ => throw new InvalidOperationException("Unreachable"), + }; + } +} \ No newline at end of file diff --git a/VYaml.SourceGenerator/Shims/GlobalAliases.cs b/VYaml.SourceGenerator/Shims/GlobalAliases.cs new file mode 100644 index 0000000..ae7319d --- /dev/null +++ b/VYaml.SourceGenerator/Shims/GlobalAliases.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Copied from https://github.com/dotnet/runtime/blob/1473deaa50785b956edd7d078e68c0581c1b4d95/src/libraries/Common/src/Roslyn/GlobalAliases.cs + +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions; + +/// +/// Simple wrapper class around an immutable array so we can have the value-semantics needed for the incremental +/// generator to know when a change actually happened and it should run later transform stages. +/// +internal sealed class GlobalAliases : IEquatable +{ + public static readonly GlobalAliases Empty = new(ImmutableArray<(string aliasName, string symbolName)>.Empty); + + public readonly ImmutableArray<(string aliasName, string symbolName)> AliasAndSymbolNames; + + private int _hashCode; + + private GlobalAliases(ImmutableArray<(string aliasName, string symbolName)> aliasAndSymbolNames) + { + AliasAndSymbolNames = aliasAndSymbolNames; + } + + public static GlobalAliases Create(ImmutableArray<(string aliasName, string symbolName)> aliasAndSymbolNames) + { + return aliasAndSymbolNames.IsEmpty ? Empty : new GlobalAliases(aliasAndSymbolNames); + } + + public static GlobalAliases Concat(GlobalAliases ga1, GlobalAliases ga2) + { + if (ga1.AliasAndSymbolNames.Length == 0) + return ga2; + + if (ga2.AliasAndSymbolNames.Length == 0) + return ga1; + + return new(ga1.AliasAndSymbolNames.AddRange(ga2.AliasAndSymbolNames)); + } + + public override int GetHashCode() + { + if (_hashCode == 0) + { + var hashCode = 0; + foreach (var tuple in this.AliasAndSymbolNames) + hashCode = HashCode.Combine(tuple.GetHashCode(), hashCode); + + _hashCode = hashCode == 0 ? 1 : hashCode; + } + + return _hashCode; + } + + public override bool Equals(object? obj) + => this.Equals(obj as GlobalAliases); + + public bool Equals(GlobalAliases? aliases) + { + if (aliases is null) + return false; + + if (ReferenceEquals(this, aliases)) + return true; + + if (this.AliasAndSymbolNames == aliases.AliasAndSymbolNames) + return true; + + return this.AliasAndSymbolNames.AsSpan().SequenceEqual(aliases.AliasAndSymbolNames.AsSpan()); + } +} diff --git a/VYaml.SourceGenerator/Shims/ISyntaxHelper.cs b/VYaml.SourceGenerator/Shims/ISyntaxHelper.cs new file mode 100644 index 0000000..76a9704 --- /dev/null +++ b/VYaml.SourceGenerator/Shims/ISyntaxHelper.cs @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Copied from https://github.com/dotnet/runtime/blob/1473deaa50785b956edd7d078e68c0581c1b4d95/src/libraries/Common/src/Roslyn/ISyntaxHelper.cs + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions +{ + internal interface ISyntaxHelper + { + bool IsCaseSensitive { get; } + + bool IsValidIdentifier(string name); + + bool IsAnyNamespaceBlock(SyntaxNode node); + + bool IsAttributeList(SyntaxNode node); + SeparatedSyntaxList GetAttributesOfAttributeList(SyntaxNode node); + + void AddAttributeTargets(SyntaxNode node, ref ValueListBuilder targets); + + bool IsAttribute(SyntaxNode node); + SyntaxNode GetNameOfAttribute(SyntaxNode node); + + bool IsLambdaExpression(SyntaxNode node); + + SyntaxToken GetUnqualifiedIdentifierOfName(SyntaxNode node); + + /// + /// must be a compilation unit or namespace block. + /// + void AddAliases(SyntaxNode node, ref ValueListBuilder<(string aliasName, string symbolName)> aliases, bool global); + void AddAliases(CompilationOptions options, ref ValueListBuilder<(string aliasName, string symbolName)> aliases); + + bool ContainsGlobalAliases(SyntaxNode root); + } + + internal abstract class AbstractSyntaxHelper : ISyntaxHelper + { + public abstract bool IsCaseSensitive { get; } + + public abstract bool IsValidIdentifier(string name); + + public abstract SyntaxToken GetUnqualifiedIdentifierOfName(SyntaxNode name); + + public abstract bool IsAnyNamespaceBlock(SyntaxNode node); + + public abstract bool IsAttribute(SyntaxNode node); + public abstract SyntaxNode GetNameOfAttribute(SyntaxNode node); + + public abstract bool IsAttributeList(SyntaxNode node); + public abstract SeparatedSyntaxList GetAttributesOfAttributeList(SyntaxNode node); + public abstract void AddAttributeTargets(SyntaxNode node, ref ValueListBuilder targets); + + public abstract bool IsLambdaExpression(SyntaxNode node); + + public abstract void AddAliases(SyntaxNode node, ref ValueListBuilder<(string aliasName, string symbolName)> aliases, bool global); + public abstract void AddAliases(CompilationOptions options, ref ValueListBuilder<(string aliasName, string symbolName)> aliases); + + public abstract bool ContainsGlobalAliases(SyntaxNode root); + } +} diff --git a/VYaml.SourceGenerator/Shims/ImmutableArrayValueComparer.cs b/VYaml.SourceGenerator/Shims/ImmutableArrayValueComparer.cs new file mode 100644 index 0000000..7c76832 --- /dev/null +++ b/VYaml.SourceGenerator/Shims/ImmutableArrayValueComparer.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Copied from https://github.com/dotnet/runtime/blob/1473deaa50785b956edd7d078e68c0581c1b4d95/src/libraries/Common/src/Roslyn/SyntaxValueProvider.ImmutableArrayValueComparer.cs + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions; + +internal static partial class SyntaxValueProviderExtensions +{ + private sealed class ImmutableArrayValueComparer : IEqualityComparer> + { + public static readonly IEqualityComparer> Instance = new ImmutableArrayValueComparer(); + + public bool Equals(ImmutableArray x, ImmutableArray y) + => x.SequenceEqual(y, EqualityComparer.Default); + + public int GetHashCode(ImmutableArray obj) + { + var hashCode = 0; + foreach (var value in obj) + hashCode = HashCode.Combine(hashCode, EqualityComparer.Default.GetHashCode(value!)); + + return hashCode; + } + } +} \ No newline at end of file diff --git a/VYaml.SourceGenerator/Shims/SyntaxValueProvider_ForAttributeWithMetadataName.cs b/VYaml.SourceGenerator/Shims/SyntaxValueProvider_ForAttributeWithMetadataName.cs new file mode 100644 index 0000000..0da2d9b --- /dev/null +++ b/VYaml.SourceGenerator/Shims/SyntaxValueProvider_ForAttributeWithMetadataName.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Copied from https://github.com/dotnet/runtime/blob/1473deaa50785b956edd7d078e68c0581c1b4d95/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithMetadataName.cs + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using System.Threading; + +using Microsoft.CodeAnalysis; + +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions; + +internal readonly struct GeneratorAttributeSyntaxContext +{ + /// + /// The syntax node the attribute is attached to. For example, with [CLSCompliant] class C { } this would + /// the class declaration node. + /// + public SyntaxNode TargetNode { get; } + + /// + /// The symbol that the attribute is attached to. For example, with [CLSCompliant] class C { } this would be + /// the for "C". + /// + public ISymbol TargetSymbol { get; } + + /// + /// Semantic model for the file that is contained within. + /// + public SemanticModel SemanticModel { get; } + + /// + /// s for any matching attributes on . Always non-empty. All + /// these attributes will have an whose fully qualified name metadata + /// name matches the name requested in . + /// + /// To get the entire list of attributes, use on . + /// + /// + public ImmutableArray Attributes { get; } + + internal GeneratorAttributeSyntaxContext( + SyntaxNode targetNode, + ISymbol targetSymbol, + SemanticModel semanticModel, + ImmutableArray attributes) + { + TargetNode = targetNode; + TargetSymbol = targetSymbol; + SemanticModel = semanticModel; + Attributes = attributes; + } +} + +internal static partial class SyntaxValueProviderExtensions +{ +#if false + + // Deviation from roslyn. We do not support attributes that are nested or generic. That's ok as that's not a + // scenario that ever arises in our generators. + + private static readonly char[] s_nestedTypeNameSeparators = new char[] { '+' }; + + private static readonly SymbolDisplayFormat s_metadataDisplayFormat = + SymbolDisplayFormat.QualifiedNameArityFormat.AddCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.UsePlusForNestedTypes); + +#endif + + /// + /// Creates an that can provide a transform over all s if that node has an attribute on it that binds to a with the + /// same fully-qualified metadata as the provided . should be the fully-qualified, metadata name of the attribute, including the + /// Attribute suffix. For example "System.CLSCompliantAttribute for . + /// + /// A function that determines if the given attribute target () should be transformed. Nodes that do not pass this + /// predicate will not have their attributes looked at at all. + /// A function that performs the transform. This will only be passed nodes that return for and which have a matching whose + /// has the same fully qualified, metadata name as . + public static IncrementalValuesProvider ForAttributeWithMetadataName( + this SyntaxValueProvider @this, + IncrementalGeneratorInitializationContext context, + string fullyQualifiedMetadataName, + Func predicate, + Func transform) + { +#if false + + // Deviation from roslyn. We do not support attributes that are nested or generic. That's ok as that's not a + // scenario that ever arises in our generators. + + var metadataName = fullyQualifiedMetadataName.Contains('+') + ? MetadataTypeName.FromFullName(fullyQualifiedMetadataName.Split(s_nestedTypeNameSeparators).Last()) + : MetadataTypeName.FromFullName(fullyQualifiedMetadataName); + + var nodesWithAttributesMatchingSimpleName = @this.ForAttributeWithSimpleName(context, metadataName.UnmangledTypeName, predicate); + +#else + + var lastDotIndex = fullyQualifiedMetadataName.LastIndexOf('.'); + Debug.Assert(lastDotIndex > 0); + var unmangledTypeName = fullyQualifiedMetadataName.Substring(lastDotIndex + 1); + + var nodesWithAttributesMatchingSimpleName = @this.ForAttributeWithSimpleName(context, unmangledTypeName, predicate); + +#endif + + var compilationAndGroupedNodesProvider = nodesWithAttributesMatchingSimpleName + .Combine(context.CompilationProvider) + /*.WithTrackingName("compilationAndGroupedNodes_ForAttributeWithMetadataName")*/; + + var syntaxHelper = CSharpSyntaxHelper.Instance; + var finalProvider = compilationAndGroupedNodesProvider.SelectMany((tuple, cancellationToken) => + { + var ((syntaxTree, syntaxNodes), compilation) = tuple; + Debug.Assert(syntaxNodes.All(n => n.SyntaxTree == syntaxTree)); + + using var result = new ValueListBuilder(Span.Empty); + if (!syntaxNodes.IsEmpty) + { + var semanticModel = compilation.GetSemanticModel(syntaxTree); + + foreach (var targetNode in syntaxNodes) + { + cancellationToken.ThrowIfCancellationRequested(); + + var targetSymbol = + targetNode is ICompilationUnitSyntax compilationUnit ? semanticModel.Compilation.Assembly : + syntaxHelper.IsLambdaExpression(targetNode) ? semanticModel.GetSymbolInfo(targetNode, cancellationToken).Symbol : + semanticModel.GetDeclaredSymbol(targetNode, cancellationToken); + if (targetSymbol is null) + continue; + + var attributes = getMatchingAttributes(targetNode, targetSymbol, fullyQualifiedMetadataName); + if (attributes.Length > 0) + { + result.Append(transform( + new GeneratorAttributeSyntaxContext(targetNode, targetSymbol, semanticModel, attributes), + cancellationToken)); + } + } + } + + return result.AsSpan().ToImmutableArray(); + })/*.WithTrackingName("result_ForAttributeWithMetadataName")*/; + + return finalProvider; + + static ImmutableArray getMatchingAttributes( + SyntaxNode attributeTarget, + ISymbol symbol, + string fullyQualifiedMetadataName) + { + var targetSyntaxTree = attributeTarget.SyntaxTree; + var result = new ValueListBuilder(Span.Empty); + + try + { + addMatchingAttributes(ref result, symbol.GetAttributes()); + addMatchingAttributes(ref result, (symbol as IMethodSymbol)?.GetReturnTypeAttributes()); + + if (symbol is IAssemblySymbol assemblySymbol) + { + foreach (var module in assemblySymbol.Modules) + addMatchingAttributes(ref result, module.GetAttributes()); + } + + return result.AsSpan().ToImmutableArray(); + } + finally + { + result.Dispose(); + } + + void addMatchingAttributes( + ref ValueListBuilder result, + ImmutableArray? attributes) + { + if (!attributes.HasValue) + return; + + foreach (var attribute in attributes.Value) + { + if (attribute.ApplicationSyntaxReference?.SyntaxTree == targetSyntaxTree && + attribute.AttributeClass?.ToDisplayString(/*s_metadataDisplayFormat*/) == fullyQualifiedMetadataName) + { + result.Append(attribute); + } + } + } + } + } +} diff --git a/VYaml.SourceGenerator/Shims/SyntaxValueProvider_ForAttributeWithSimpleName.cs b/VYaml.SourceGenerator/Shims/SyntaxValueProvider_ForAttributeWithSimpleName.cs new file mode 100644 index 0000000..193f8dd --- /dev/null +++ b/VYaml.SourceGenerator/Shims/SyntaxValueProvider_ForAttributeWithSimpleName.cs @@ -0,0 +1,455 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Copied from https://github.com/dotnet/runtime/blob/1473deaa50785b956edd7d078e68c0581c1b4d95/src/libraries/Common/src/Roslyn/SyntaxValueProvider_ForAttributeWithSimpleName.cs + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Aliases = System.Collections.Generic.ValueListBuilder<(string aliasName, string symbolName)>; + +namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions; + +internal static partial class SyntaxValueProviderExtensions +{ + // Normal class as Runtime does not seem to support records currently. + + /// + /// Information computed about a particular tree. Cached so we don't repeatedly recompute this important + /// information each time the incremental pipeline is rerun. + /// + private sealed class SyntaxTreeInfo : IEquatable + { + public readonly SyntaxTree Tree; + public readonly bool ContainsGlobalAliases; + public readonly bool ContainsAttributeList; + + public SyntaxTreeInfo(SyntaxTree tree, bool containsGlobalAliases, bool containsAttributeList) + { + Tree = tree; + ContainsGlobalAliases = containsGlobalAliases; + ContainsAttributeList = containsAttributeList; + } + + public bool Equals(SyntaxTreeInfo? other) + => Tree == other?.Tree; + + public override bool Equals(object? obj) + => this.Equals(obj as SyntaxTreeInfo); + + public override int GetHashCode() + => Tree.GetHashCode(); + } + + /// + /// Caching of syntax-tree to the info we've computed about it. Used because compilations will have thousands of + /// trees, and the incremental pipeline will get called back for *all* of them each time a compilation changes. We + /// do not want to continually recompute this data over and over again each time that happens given that normally + /// only one tree will be different. We also do not want to create an IncrementalValuesProvider that yield this + /// information as that will mean we have a node in the tree that scales with the number of *all syntax trees*, not + /// the number of *relevant syntax trees*. This can lead to huge memory churn keeping track of a high number of + /// trees, most of which are not going to be relevant. + /// + private static readonly ConditionalWeakTable s_treeToInfo = new ConditionalWeakTable(); + +#if false + // Not used in runtime. Pooling is not a pattern here, and we use ValueListBuilder instead. + + private static readonly ObjectPool> s_stackPool = new(static () => new()); +#endif + + /// + /// Returns all syntax nodes of that match if that node has an attribute on it that + /// could possibly bind to the provided . should be the + /// simple, non-qualified, name of the attribute, including the Attribute suffix, and not containing any + /// generics, containing types, or namespaces. For example CLSCompliantAttribute for . + /// This provider understands (Import in Visual Basic) aliases and will find + /// matches even when the attribute references an alias name. For example, given: + /// + /// using XAttribute = System.CLSCompliantAttribute; + /// [X] + /// class C { } + /// + /// Then + /// context.SyntaxProvider.CreateSyntaxProviderForAttribute(nameof(CLSCompliantAttribute), (node, c) => node is ClassDeclarationSyntax) + /// will find the C class. + /// + /// + /// Note: a 'Values'-provider of arrays are returned. Each array provides all the matching nodes from a single . + /// + public static IncrementalValuesProvider<(SyntaxTree tree, ImmutableArray matches)> ForAttributeWithSimpleName( + this SyntaxValueProvider @this, + IncrementalGeneratorInitializationContext context, + string simpleName, + Func predicate) + { + var syntaxHelper = CSharpSyntaxHelper.Instance; + + // Create a provider over all the syntax trees in the compilation. This is better than CreateSyntaxProvider as + // using SyntaxTrees is purely syntax and will not update the incremental node for a tree when another tree is + // changed. CreateSyntaxProvider will have to rerun all incremental nodes since it passes along the + // SemanticModel, and that model is updated whenever any tree changes (since it is tied to the compilation). + var syntaxTreesProvider = context.CompilationProvider + .SelectMany((compilation, cancellationToken) => compilation.SyntaxTrees + .Select(tree => GetTreeInfo(tree, syntaxHelper, cancellationToken)) + .Where(info => info.ContainsGlobalAliases || info.ContainsAttributeList)) + /*.WithTrackingName("compilationUnit_ForAttribute")*/; + + // Create a provider that provides (and updates) the global aliases for any particular file when it is edited. + var individualFileGlobalAliasesProvider = syntaxTreesProvider + .Where(info => info.ContainsGlobalAliases) + .Select((info, cancellationToken) => getGlobalAliasesInCompilationUnit(info.Tree.GetRoot(cancellationToken))) + /*.WithTrackingName("individualFileGlobalAliases_ForAttribute")*/; + + // Create an aggregated view of all global aliases across all files. This should only update when an individual + // file changes its global aliases or a file is added / removed from the compilation + var collectedGlobalAliasesProvider = individualFileGlobalAliasesProvider + .Collect() + .WithComparer(ImmutableArrayValueComparer.Instance) + /*.WithTrackingName("collectedGlobalAliases_ForAttribute")*/; + + var allUpGlobalAliasesProvider = collectedGlobalAliasesProvider + .Select(static (arrays, _) => GlobalAliases.Create(arrays.SelectMany(a => a.AliasAndSymbolNames).ToImmutableArray())) + /*.WithTrackingName("allUpGlobalAliases_ForAttribute")*/; + +#if false + + // C# does not support global aliases from compilation options. So we can just ignore this part. + + // Regenerate our data if the compilation options changed. VB can supply global aliases with compilation options, + // so we have to reanalyze everything if those changed. + var compilationGlobalAliases = _context.CompilationOptionsProvider.Select( + (o, _) => + { + var aliases = Aliases.GetInstance(); + syntaxHelper.AddAliases(o, aliases); + return GlobalAliases.Create(aliases.ToImmutableAndFree()); + }).WithTrackingName("compilationGlobalAliases_ForAttribute"); + + allUpGlobalAliasesProvider = allUpGlobalAliasesProvider + .Combine(compilationGlobalAliases) + .Select((tuple, _) => GlobalAliases.Concat(tuple.Left, tuple.Right)) + .WithTrackingName("allUpIncludingCompilationGlobalAliases_ForAttribute"); + +#endif + + // Combine the two providers so that we reanalyze every file if the global aliases change, or we reanalyze a + // particular file when it's compilation unit changes. + var syntaxTreeAndGlobalAliasesProvider = syntaxTreesProvider + .Where(info => info.ContainsAttributeList) + .Combine(allUpGlobalAliasesProvider) + /*.WithTrackingName("compilationUnitAndGlobalAliases_ForAttribute")*/; + + // For each pair of compilation unit + global aliases, walk the compilation unit + var result = syntaxTreeAndGlobalAliasesProvider + .Select((tuple, c) => (tuple.Left.Tree, GetMatchingNodes(syntaxHelper, tuple.Right, tuple.Left.Tree, simpleName, predicate, c))) + .Where(tuple => tuple.Item2.Length > 0) + /*.WithTrackingName("result_ForAttribute")*/; + + return result; + + static GlobalAliases getGlobalAliasesInCompilationUnit( + SyntaxNode compilationUnit) + { + Debug.Assert(compilationUnit is ICompilationUnitSyntax); + var globalAliases = new Aliases(Span<(string aliasName, string symbolName)>.Empty); + + CSharpSyntaxHelper.Instance.AddAliases(compilationUnit, ref globalAliases, global: true); + + return GlobalAliases.Create(globalAliases.AsSpan().ToImmutableArray()); + } + } + + private static SyntaxTreeInfo GetTreeInfo( + SyntaxTree tree, ISyntaxHelper syntaxHelper, CancellationToken cancellationToken) + { + // prevent captures for the case where the item is in the tree. + return s_treeToInfo.TryGetValue(tree, out var info) + ? info + : computeTreeInfo(); + + SyntaxTreeInfo computeTreeInfo() + { + var root = tree.GetRoot(cancellationToken); + var containsGlobalAliases = syntaxHelper.ContainsGlobalAliases(root); + var containsAttributeList = ContainsAttributeList(root); + + var info = new SyntaxTreeInfo(tree, containsGlobalAliases, containsAttributeList); + return s_treeToInfo.GetValue(tree, _ => info); + } + } + + private static ImmutableArray GetMatchingNodes( + ISyntaxHelper syntaxHelper, + GlobalAliases globalAliases, + SyntaxTree syntaxTree, + string name, + Func predicate, + CancellationToken cancellationToken) + { + var compilationUnit = syntaxTree.GetRoot(cancellationToken); + Debug.Assert(compilationUnit is ICompilationUnitSyntax); + + var isCaseSensitive = syntaxHelper.IsCaseSensitive; + var comparison = isCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; + + // As we walk down the compilation unit and nested namespaces, we may encounter additional using aliases local + // to this file. Keep track of them so we can determine if they would allow an attribute in code to bind to the + // attribute being searched for. + var localAliases = new Aliases(Span<(string, string)>.Empty); + var nameHasAttributeSuffix = name.HasAttributeSuffix(isCaseSensitive); + + // Used to ensure that as we recurse through alias names to see if they could bind to attributeName that we + // don't get into cycles. + + var seenNames = new ValueListBuilder(Span.Empty); + var results = new ValueListBuilder(Span.Empty); + var attributeTargets = new ValueListBuilder(Span.Empty); + + try + { + processCompilationUnit(compilationUnit, ref localAliases, ref seenNames, ref results, ref attributeTargets); + + if (results.Length == 0) + return ImmutableArray.Empty; + + return results.AsSpan().ToArray().Distinct().ToImmutableArray(); + } + finally + { + attributeTargets.Dispose(); + results.Dispose(); + seenNames.Dispose(); + } + + void processCompilationUnit( + SyntaxNode compilationUnit, + ref Aliases localAliases, + ref ValueListBuilder seenNames, + ref ValueListBuilder results, + ref ValueListBuilder attributeTargets) + { + cancellationToken.ThrowIfCancellationRequested(); + + syntaxHelper.AddAliases(compilationUnit, ref localAliases, global: false); + + processCompilationOrNamespaceMembers(compilationUnit, ref localAliases, ref seenNames, ref results, ref attributeTargets); + } + + void processCompilationOrNamespaceMembers( + SyntaxNode node, + ref Aliases localAliases, + ref ValueListBuilder seenNames, + ref ValueListBuilder results, + ref ValueListBuilder attributeTargets) + { + cancellationToken.ThrowIfCancellationRequested(); + + foreach (var child in node.ChildNodesAndTokens()) + { + if (child.IsNode) + { + var childNode = child.AsNode()!; + if (syntaxHelper.IsAnyNamespaceBlock(childNode)) + processNamespaceBlock(childNode, ref localAliases, ref seenNames, ref results, ref attributeTargets); + else + processMember(childNode, ref localAliases, ref seenNames, ref results, ref attributeTargets); + } + } + } + + void processNamespaceBlock( + SyntaxNode namespaceBlock, + ref Aliases localAliases, + ref ValueListBuilder seenNames, + ref ValueListBuilder results, + ref ValueListBuilder attributeTargets) + { + cancellationToken.ThrowIfCancellationRequested(); + + var localAliasCount = localAliases.Length; + syntaxHelper.AddAliases(namespaceBlock, ref localAliases, global: false); + + processCompilationOrNamespaceMembers( + namespaceBlock, ref localAliases, ref seenNames, ref results, ref attributeTargets); + + // after recursing into this namespace, dump any local aliases we added from this namespace decl itself. + localAliases.Length = localAliasCount; + } + + void processMember( + SyntaxNode member, + ref Aliases localAliases, + ref ValueListBuilder seenNames, + ref ValueListBuilder results, + ref ValueListBuilder attributeTargets) + { + cancellationToken.ThrowIfCancellationRequested(); + + // nodes can be arbitrarily deep. Use an explicit stack over recursion to prevent a stack-overflow. + var nodeStack = new ValueListBuilder(Span.Empty); + nodeStack.Append(member); + + try + { + while (nodeStack.Length > 0) + { + var node = nodeStack.Pop(); + + if (syntaxHelper.IsAttributeList(node)) + { + foreach (var attribute in syntaxHelper.GetAttributesOfAttributeList(node)) + { + // Have to lookup both with the name in the attribute, as well as adding the 'Attribute' suffix. + // e.g. if there is [X] then we have to lookup with X and with XAttribute. + var simpleAttributeName = syntaxHelper.GetUnqualifiedIdentifierOfName( + syntaxHelper.GetNameOfAttribute(attribute)).ValueText; + if (matchesAttributeName(ref localAliases, ref seenNames, simpleAttributeName, withAttributeSuffix: false) || + matchesAttributeName(ref localAliases, ref seenNames, simpleAttributeName, withAttributeSuffix: true)) + { + attributeTargets.Length = 0; + syntaxHelper.AddAttributeTargets(node, ref attributeTargets); + + foreach (var target in attributeTargets.AsSpan()) + { + if (predicate(target, cancellationToken)) + results.Append(target); + } + + break; + } + } + + // attributes can't have attributes inside of them. so no need to recurse when we're done. + } + else + { + // For any other node, just keep recursing deeper to see if we can find an attribute. Note: we cannot + // terminate the search anywhere as attributes may be found on things like local functions, and that + // means having to dive deep into statements and expressions. + var childNodesAndTokens = node.ChildNodesAndTokens(); + + // Avoid performance issue in ChildSyntaxList when iterating the child list in reverse + // (see https://github.com/dotnet/roslyn/issues/66475) by iterating forward first to + // ensure child nodes are realized. + foreach (var childNode in childNodesAndTokens) + { + } + + foreach (var child in childNodesAndTokens.Reverse()) + { + if (child.IsNode) + nodeStack.Append(child.AsNode()!); + } + } + + } + } + finally + { + nodeStack.Dispose(); + } + } + + // Checks if `name` is equal to `matchAgainst`. if `withAttributeSuffix` is true, then + // will check if `name` + "Attribute" is equal to `matchAgainst` + bool matchesName(string name, string matchAgainst, bool withAttributeSuffix) + { + if (withAttributeSuffix) + { + return name.Length + "Attribute".Length == matchAgainst.Length && + matchAgainst.HasAttributeSuffix(isCaseSensitive) && + matchAgainst.StartsWith(name, comparison); + } + else + { + return name.Equals(matchAgainst, comparison); + } + } + + bool matchesAttributeName( + ref Aliases localAliases, + ref ValueListBuilder seenNames, + string currentAttributeName, + bool withAttributeSuffix) + { + // If the names match, we're done. + if (withAttributeSuffix) + { + if (nameHasAttributeSuffix && + matchesName(currentAttributeName, name, withAttributeSuffix)) + { + return true; + } + } + else + { + if (matchesName(currentAttributeName, name, withAttributeSuffix: false)) + return true; + } + + // Otherwise, keep searching through aliases. Check that this is the first time seeing this name so we + // don't infinite recurse in error code where aliases reference each other. + // + // note: as we recurse up the aliases, we do not want to add the attribute suffix anymore. aliases must + // reference the actual real name of the symbol they are aliasing. + foreach (var seenName in seenNames.AsSpan()) + { + if (seenName == currentAttributeName) + return false; + } + + seenNames.Append(currentAttributeName); + + foreach (var (aliasName, symbolName) in localAliases.AsSpan()) + { + // see if user wrote `[SomeAlias]`. If so, if we find a `using SomeAlias = ...` recurse using the + // ... name portion to see if it might bind to the attr name the caller is searching for. + if (matchesName(currentAttributeName, aliasName, withAttributeSuffix) && + matchesAttributeName(ref localAliases, ref seenNames, symbolName, withAttributeSuffix: false)) + { + return true; + } + } + + foreach (var (aliasName, symbolName) in globalAliases.AliasAndSymbolNames) + { + if (matchesName(currentAttributeName, aliasName, withAttributeSuffix) && + matchesAttributeName(ref localAliases, ref seenNames, symbolName, withAttributeSuffix: false)) + { + return true; + } + } + + seenNames.Pop(); + return false; + } + } + + private static bool ContainsAttributeList(SyntaxNode node) + { + if (node.IsKind(SyntaxKind.AttributeList)) + return true; + + foreach (SyntaxNodeOrToken child in node.ChildNodesAndTokens()) + { + if (child.IsToken) + continue; + + SyntaxNode? childNode = child.AsNode()!; + if (ContainsAttributeList(childNode)) + return true; + } + + return false; + } +} diff --git a/VYaml.SourceGenerator/Shims/ValueListHelper.cs b/VYaml.SourceGenerator/Shims/ValueListHelper.cs new file mode 100644 index 0000000..1c4dc11 --- /dev/null +++ b/VYaml.SourceGenerator/Shims/ValueListHelper.cs @@ -0,0 +1,213 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Copied from https://github.com/dotnet/runtime/blob/1473deaa50785b956edd7d078e68c0581c1b4d95/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ValueListBuilder.cs + +using System.Buffers; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace System.Collections.Generic +{ + internal ref partial struct ValueListBuilder + { + private Span _span; + private T[]? _arrayFromPool; + private int _pos; + + public ValueListBuilder(Span initialSpan) + { + _span = initialSpan; + _arrayFromPool = null; + _pos = 0; + } + + public int Length + { + get => _pos; + set + { + Debug.Assert(value >= 0); + Debug.Assert(value <= _span.Length); + _pos = value; + } + } + + public ref T this[int index] + { + get + { + Debug.Assert(index < _pos); + return ref _span[index]; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Append(T item) + { + int pos = _pos; + + // Workaround for https://github.com/dotnet/runtime/issues/72004 + Span span = _span; + if ((uint)pos < (uint)span.Length) + { + span[pos] = item; + _pos = pos + 1; + } + else + { + AddWithResize(item); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Append(scoped ReadOnlySpan source) + { + int pos = _pos; + Span span = _span; + if (source.Length == 1 && (uint)pos < (uint)span.Length) + { + span[pos] = source[0]; + _pos = pos + 1; + } + else + { + AppendMultiChar(source); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void AppendMultiChar(scoped ReadOnlySpan source) + { + if ((uint)(_pos + source.Length) > (uint)_span.Length) + { + Grow(_span.Length - _pos + source.Length); + } + + source.CopyTo(_span.Slice(_pos)); + _pos += source.Length; + } + + public void Insert(int index, scoped ReadOnlySpan source) + { + Debug.Assert(index >= 0 && index <= _pos); + + if ((uint)(_pos + source.Length) > (uint)_span.Length) + { + Grow(source.Length); + } + + _span.Slice(0, _pos).CopyTo(_span.Slice(source.Length)); + source.CopyTo(_span); + _pos += source.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AppendSpan(int length) + { + Debug.Assert(length >= 0); + + int pos = _pos; + Span span = _span; + if ((ulong)(uint)pos + (ulong)(uint)length <= (ulong)(uint)span.Length) // same guard condition as in Span.Slice on 64-bit + { + _pos = pos + length; + return span.Slice(pos, length); + } + else + { + return AppendSpanWithGrow(length); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private Span AppendSpanWithGrow(int length) + { + int pos = _pos; + Grow(_span.Length - pos + length); + _pos += length; + return _span.Slice(pos, length); + } + + // Hide uncommon path + [MethodImpl(MethodImplOptions.NoInlining)] + private void AddWithResize(T item) + { + Debug.Assert(_pos == _span.Length); + int pos = _pos; + Grow(1); + _span[pos] = item; + _pos = pos + 1; + } + + public ReadOnlySpan AsSpan() + { + return _span.Slice(0, _pos); + } + + public bool TryCopyTo(Span destination, out int itemsWritten) + { + if (_span.Slice(0, _pos).TryCopyTo(destination)) + { + itemsWritten = _pos; + return true; + } + + itemsWritten = 0; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Pop() + { + _pos--; + return _span[_pos]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + T[]? toReturn = _arrayFromPool; + if (toReturn != null) + { + _arrayFromPool = null; + ArrayPool.Shared.Return(toReturn); + } + } + + // Note that consuming implementations depend on the list only growing if it's absolutely + // required. If the list is already large enough to hold the additional items be added, + // it must not grow. The list is used in a number of places where the reference is checked + // and it's expected to match the initial reference provided to the constructor if that + // span was sufficiently large. + private void Grow(int additionalCapacityRequired = 1) + { + const int ArrayMaxLength = 0x7FFFFFC7; // same as Array.MaxLength + + // Double the size of the span. If it's currently empty, default to size 4, + // although it'll be increased in Rent to the pool's minimum bucket size. + int nextCapacity = Math.Max(_span.Length != 0 ? _span.Length * 2 : 4, _span.Length + additionalCapacityRequired); + + // If the computed doubled capacity exceeds the possible length of an array, then we + // want to downgrade to either the maximum array length if that's large enough to hold + // an additional item, or the current length + 1 if it's larger than the max length, in + // which case it'll result in an OOM when calling Rent below. In the exceedingly rare + // case where _span.Length is already int.MaxValue (in which case it couldn't be a managed + // array), just use that same value again and let it OOM in Rent as well. + if ((uint)nextCapacity > ArrayMaxLength) + { + nextCapacity = Math.Max(Math.Max(_span.Length + 1, ArrayMaxLength), _span.Length); + } + + T[] array = ArrayPool.Shared.Rent(nextCapacity); + _span.CopyTo(array); + + T[]? toReturn = _arrayFromPool; + _span = _arrayFromPool = array; + if (toReturn != null) + { + ArrayPool.Shared.Return(toReturn); + } + } + } +} \ No newline at end of file diff --git a/VYaml.SourceGenerator/SymbolExtensions.cs b/VYaml.SourceGenerator/SymbolExtensions.cs new file mode 100644 index 0000000..de5c3f9 --- /dev/null +++ b/VYaml.SourceGenerator/SymbolExtensions.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace VYaml.SourceGenerator; + +static class SymbolExtensions +{ + public static bool ContainsAttribute(this ISymbol symbol, INamedTypeSymbol attribtue) + { + return symbol.GetAttributes().Any(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, attribtue)); + } + + public static AttributeData? GetAttribute(this ISymbol symbol, INamedTypeSymbol attribtue) + { + return symbol.GetAttributes().FirstOrDefault(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, attribtue)); + } + + public static AttributeData? GetImplAttribute(this ISymbol symbol, INamedTypeSymbol implAttribtue) + { + return symbol.GetAttributes().FirstOrDefault(x => + { + if (x.AttributeClass == null) return false; + if (x.AttributeClass.EqualsUnconstructedGenericType(implAttribtue)) return true; + + foreach (var item in x.AttributeClass.GetAllBaseTypes()) + { + if (item.EqualsUnconstructedGenericType(implAttribtue)) + { + return true; + } + } + return false; + }); + } + + public static IEnumerable GetAllMembers(this INamedTypeSymbol symbol, bool withoutOverride = true) + { + // Iterate Parent -> Derived + if (symbol.BaseType != null) + { + foreach (var item in GetAllMembers(symbol.BaseType)) + { + // override item already iterated in parent type + if (!withoutOverride || !item.IsOverride) + { + yield return item; + } + } + } + + foreach (var item in symbol.GetMembers()) + { + if (!withoutOverride || !item.IsOverride) + { + yield return item; + } + } + } + + public static bool InheritsFrom(this INamedTypeSymbol symbol, INamedTypeSymbol baseSymbol) + { + var baseName = baseSymbol.ToString(); + while (true) + { + if (symbol.ToString() == baseName) + { + return true; + } + if (symbol.BaseType != null) + { + symbol = symbol.BaseType; + continue; + } + break; + } + return false; + } + + public static IEnumerable GetAllBaseTypes(this INamedTypeSymbol symbol) + { + var t = symbol.BaseType; + while (t != null) + { + yield return t; + t = t.BaseType; + } + } + + public static bool EqualsUnconstructedGenericType(this INamedTypeSymbol left, INamedTypeSymbol right) + { + var l = left.IsGenericType ? left.ConstructUnboundGenericType() : left; + var r = right.IsGenericType ? right.ConstructUnboundGenericType() : right; + return SymbolEqualityComparer.Default.Equals(l, r); + } +} diff --git a/VYaml.SourceGenerator/TypeMeta.cs b/VYaml.SourceGenerator/TypeMeta.cs new file mode 100644 index 0000000..ec8fe1f --- /dev/null +++ b/VYaml.SourceGenerator/TypeMeta.cs @@ -0,0 +1,117 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace VYaml.SourceGenerator; + +class UnionMeta +{ + public string SubTypeTag { get; set; } + public INamedTypeSymbol SubTypeSymbol { get; set; } + public string FullTypeName { get; } + + public UnionMeta(string subTypeTag, INamedTypeSymbol subTypeSymbol) + { + SubTypeTag = subTypeTag; + SubTypeSymbol = subTypeSymbol; + FullTypeName = subTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + } +} + +class TypeMeta +{ + public TypeDeclarationSyntax Syntax { get; } + public INamedTypeSymbol Symbol { get; } + public AttributeData YamlObjectAttribute { get; } + public string TypeName { get; } + public string FullTypeName { get; } + public IReadOnlyList Constructors { get; } + public IReadOnlyList UnionMetas { get; } + public NamingConvention NamingConvention { get; } + + public IReadOnlyList MemberMetas => memberMetas ??= GetSerializeMembers(); + public bool IsUnion => UnionMetas.Count > 0; + + ReferenceSymbols references; + MemberMeta[]? memberMetas; + + public TypeMeta( + TypeDeclarationSyntax syntax, + INamedTypeSymbol symbol, + AttributeData yamlObjectAttribute, + ReferenceSymbols references) + { + Syntax = syntax; + Symbol = symbol; + this.references = references; + + TypeName = symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); + FullTypeName = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + + YamlObjectAttribute = yamlObjectAttribute; + + foreach (var arg in YamlObjectAttribute.ConstructorArguments) + { + if (SymbolEqualityComparer.Default.Equals(arg.Type, references.NamingConventionEnum)) + { + NamingConvention = arg.Value != null + ? (NamingConvention)arg.Value + : NamingConvention.LowerCamelCase; + break; + } + } + + Constructors = symbol.InstanceConstructors + .Where(x => !x.IsImplicitlyDeclared) // remove empty ctor(struct always generate it), record's clone ctor + .ToArray(); + + UnionMetas = symbol.GetAttributes() + .Where(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, references.YamlObjectUnionAttribute)) + .Where(x => x.ConstructorArguments.Length == 2) + .Select(x => new UnionMeta( + (string)x.ConstructorArguments[0].Value!, + (INamedTypeSymbol)x.ConstructorArguments[1].Value!)) + .ToArray(); + } + + public bool IsPartial() + { + return Syntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)); + } + + public bool IsNested() + { + return Syntax.Parent is TypeDeclarationSyntax; + } + + MemberMeta[] GetSerializeMembers() + { + if (memberMetas == null) + { + memberMetas = Symbol.GetAllMembers() // iterate includes parent type + .Where(x => x is (IFieldSymbol or IPropertySymbol) and { IsStatic: false, IsImplicitlyDeclared: false }) + .Where(x => + { + if (x.ContainsAttribute(references.YamlIgnoreAttribute)) return false; + if (x.DeclaredAccessibility != Accessibility.Public) return false; + + if (x is IPropertySymbol p) + { + // set only can't be serializable member + if (p.GetMethod == null && p.SetMethod != null) + { + return false; + } + if (p.IsIndexer) return false; + } + return true; + }) + .Select((x, i) => new MemberMeta(x, references, NamingConvention, i)) + .OrderBy(x => x.Order) + .ToArray(); + } + return memberMetas; + } +} diff --git a/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj b/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj new file mode 100644 index 0000000..e54b49f --- /dev/null +++ b/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj @@ -0,0 +1,26 @@ + + + + netstandard2.1 + false + enable + 12 + + true + true + + VYaml.SourceGenerator + VYaml.SourceGenerator + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/VYaml.SourceGenerator/VYamlIncrementalSourceGenerator.cs b/VYaml.SourceGenerator/VYamlIncrementalSourceGenerator.cs new file mode 100644 index 0000000..2c46c40 --- /dev/null +++ b/VYaml.SourceGenerator/VYamlIncrementalSourceGenerator.cs @@ -0,0 +1,689 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; + +namespace VYaml.SourceGenerator; + +[Generator] +public class VYamlIncrementalSourceGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var provider = context.SyntaxProvider + .ForAttributeWithMetadataName( + context, + "VYaml.Annotations.YamlObjectAttribute", + static (node, cancellation) => + { + return node is ClassDeclarationSyntax + or StructDeclarationSyntax + or RecordDeclarationSyntax + or InterfaceDeclarationSyntax; + }, + static (context, cancellation) => { return context; }) + .Combine(context.CompilationProvider) + .WithComparer(Comparer.Instance); + + // Generate the source code. + context.RegisterSourceOutput( + context.CompilationProvider.Combine(provider.Collect()), + (sourceProductionContext, t) => + { + var (compilation, list) = t; + var references = ReferenceSymbols.Create(compilation); + if (references is null) + { + return; + } + + var codeWriter = new CodeWriter(); + + foreach (var (x, _) in list) + { + var typeMeta = new TypeMeta( + (TypeDeclarationSyntax)x.TargetNode, + (INamedTypeSymbol)x.TargetSymbol, + x.Attributes.First(), + references); + + if (TryEmit(typeMeta, codeWriter, references, sourceProductionContext)) + { + var fullType = typeMeta.FullTypeName + .Replace("global::", "") + .Replace("<", "_") + .Replace(">", "_"); + + sourceProductionContext.AddSource($"{fullType}.YamlFormatter.g.cs", codeWriter.ToString()); + } + codeWriter.Clear(); + } + }); + } + + static bool TryEmit( + TypeMeta typeMeta, + CodeWriter codeWriter, + ReferenceSymbols references, + in SourceProductionContext context) + { + try + { + var error = false; + + // verify is partial + if (!typeMeta.IsPartial()) + { + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.MustBePartial, + typeMeta.Syntax.Identifier.GetLocation(), + typeMeta.Symbol.Name)); + error = true; + } + + // nested is not allowed + if (typeMeta.IsNested()) + { + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.NestedNotAllow, + typeMeta.Syntax.Identifier.GetLocation(), + typeMeta.Symbol.Name)); + error = true; + } + + // verify abstract/interface + if (typeMeta.Symbol.IsAbstract) + { + if (!typeMeta.IsUnion) + { + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.AbstractMustUnion, + typeMeta.Syntax.Identifier.GetLocation(), + typeMeta.TypeName)); + error = true; + } + } + + // verify union + if (typeMeta.IsUnion) + { + if (!typeMeta.Symbol.IsAbstract) + { + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.ConcreteTypeCantBeUnion, + typeMeta.Syntax.Identifier.GetLocation(), + typeMeta.TypeName)); + error = true; + } + + // verify tag duplication + foreach (var tagGroup in typeMeta.UnionMetas.GroupBy(x => x.SubTypeTag)) + { + if (tagGroup.Count() > 1) + { + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.UnionTagDuplicate, + typeMeta.Syntax.Identifier.GetLocation(), + tagGroup.Key)); + error = true; + } + } + + // verify interface impl + if (typeMeta.Symbol.TypeKind == TypeKind.Interface) + { + foreach (var unionMeta in typeMeta.UnionMetas) + { + // interface, check interfaces. + var check = unionMeta.SubTypeSymbol.IsGenericType + ? unionMeta.SubTypeSymbol.OriginalDefinition.AllInterfaces.Any(x => x.EqualsUnconstructedGenericType(typeMeta.Symbol)) + : unionMeta.SubTypeSymbol.AllInterfaces.Any(x => SymbolEqualityComparer.Default.Equals(x, typeMeta.Symbol)); + + if (!check) + { + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.UnionMemberTypeNotImplementBaseType, + typeMeta.Syntax.Identifier.GetLocation(), + typeMeta.TypeName, + unionMeta.SubTypeSymbol.Name)); + error = true; + } + } + } + // verify abstract inherit + else + { + foreach (var unionMeta in typeMeta.UnionMetas) + { + // abstract type, check base. + var check = unionMeta.SubTypeSymbol.IsGenericType + ? unionMeta.SubTypeSymbol.OriginalDefinition.GetAllBaseTypes().Any(x => x.EqualsUnconstructedGenericType(typeMeta.Symbol)) + : unionMeta.SubTypeSymbol.GetAllBaseTypes().Any(x => SymbolEqualityComparer.Default.Equals(x, typeMeta.Symbol)); + + if (!check) + { + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.UnionMemberTypeNotDerivedBaseType, + typeMeta.Syntax.Identifier.GetLocation(), + typeMeta.TypeName, + unionMeta.SubTypeSymbol.Name)); + error = true; + } + } + } + } + + if (error) + { + return false; + } + + codeWriter.AppendLine("// "); + codeWriter.AppendLine("#nullable enable"); + codeWriter.AppendLine("#pragma warning disable CS0162 // Unreachable code"); + codeWriter.AppendLine("#pragma warning disable CS0219 // Variable assigned but never used"); + codeWriter.AppendLine("#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type."); + codeWriter.AppendLine("#pragma warning disable CS8601 // Possible null reference assignment"); + codeWriter.AppendLine("#pragma warning disable CS8602 // Possible null return"); + codeWriter.AppendLine("#pragma warning disable CS8604 // Possible null reference argument for parameter"); + codeWriter.AppendLine("#pragma warning disable CS8631 // The type cannot be used as type parameter in the generic type or method"); + codeWriter.AppendLine(); + codeWriter.AppendLine("using System;"); + codeWriter.AppendLine("using VYaml.Annotations;"); + codeWriter.AppendLine("using VYaml.Parser;"); + codeWriter.AppendLine("using VYaml.Emitter;"); + codeWriter.AppendLine("using VYaml.Serialization;"); + codeWriter.AppendLine(); + + var ns = typeMeta.Symbol.ContainingNamespace; + if (!ns.IsGlobalNamespace) + { + codeWriter.AppendLine($"namespace {ns}"); + codeWriter.BeginBlock(); + } + + var typeDeclarationKeyword = (typeMeta.Symbol.IsRecord, typeMeta.Symbol.IsValueType) switch + { + (true, true) => "record struct", + (true, false) => "record", + (false, true) => "struct", + (false, false) => "class", + }; + if (typeMeta.IsUnion) + { + typeDeclarationKeyword = typeMeta.Symbol.IsRecord + ? "record" + : typeMeta.Symbol.TypeKind == TypeKind.Interface ? "interface" : "class"; + } + + using (codeWriter.BeginBlockScope($"partial {typeDeclarationKeyword} {typeMeta.TypeName}")) + { + // EmitCCtor(typeMeta, codeWriter, in context); + if (!TryEmitRegisterMethod(typeMeta, codeWriter, in context)) + { + return false; + } + if (!TryEmitFormatter(typeMeta, codeWriter, references, in context)) + { + return false; + } + } + + if (!ns.IsGlobalNamespace) + { + codeWriter.EndBlock(); + } + + codeWriter.AppendLine("#pragma warning restore CS0162 // Unreachable code"); + codeWriter.AppendLine("#pragma warning restore CS0219 // Variable assigned but never used"); + codeWriter.AppendLine("#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type."); + codeWriter.AppendLine("#pragma warning restore CS8601 // Possible null reference assignment"); + codeWriter.AppendLine("#pragma warning restore CS8602 // Possible null return"); + codeWriter.AppendLine("#pragma warning restore CS8604 // Possible null reference argument for parameter"); + codeWriter.AppendLine("#pragma warning restore CS8631 // The type cannot be used as type parameter in the generic type or method"); + return true; + } + catch (Exception ex) + { + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.UnexpectedErrorDescriptor, + Location.None, + ex.ToString())); + return false; + } + } + + static void EmitCCtor(TypeMeta typeMeta, CodeWriter codeWriter) + { + using var _ = codeWriter.BeginBlockScope($"static {typeMeta.TypeName}()"); + codeWriter.AppendLine($"__RegisterVYamlFormatter();"); + } + + static bool TryEmitRegisterMethod(TypeMeta typeMeta, CodeWriter codeWriter, in SourceProductionContext context) + { + codeWriter.AppendLine("[VYaml.Annotations.Preserve]"); + using var _ = codeWriter.BeginBlockScope("public static void __RegisterVYamlFormatter()"); + codeWriter.AppendLine($"global::VYaml.Serialization.GeneratedResolver.Register(new {typeMeta.TypeName}GeneratedFormatter());"); + return true; + } + + static bool TryEmitFormatter( + TypeMeta typeMeta, + CodeWriter codeWriter, + ReferenceSymbols references, + in SourceProductionContext context) + { + var returnType = typeMeta.Symbol.IsValueType + ? typeMeta.FullTypeName + : $"{typeMeta.FullTypeName}?"; + + codeWriter.AppendLine("[VYaml.Annotations.Preserve]"); + using var _ = codeWriter.BeginBlockScope($"public class {typeMeta.TypeName}GeneratedFormatter : IYamlFormatter<{returnType}>"); + + // Union + if (typeMeta.IsUnion) + { + return TryEmitSerializeMethodUnion(typeMeta, codeWriter, in context) && + TryEmitDeserializeMethodUnion(typeMeta, codeWriter, in context); + } + + // Default + foreach (var memberMeta in typeMeta.MemberMetas) + { + codeWriter.Append($"static readonly byte[] {memberMeta.Name}KeyUtf8Bytes = "); + codeWriter.AppendByteArrayString(memberMeta.KeyNameUtf8Bytes); + codeWriter.AppendLine($"; // {memberMeta.KeyName}", false); + codeWriter.AppendLine(); + } + + return TryEmitSerializeMethod(typeMeta, codeWriter, in context) && + TryEmitDeserializeMethod(typeMeta, codeWriter, references, in context); + } + + static bool TryEmitSerializeMethod(TypeMeta typeMeta, CodeWriter codeWriter, in SourceProductionContext context) + { + var memberMetas = typeMeta.MemberMetas; + var returnType = typeMeta.Symbol.IsValueType + ? typeMeta.FullTypeName + : $"{typeMeta.FullTypeName}?"; + + codeWriter.AppendLine("[VYaml.Annotations.Preserve]"); + using var methodScope = codeWriter.BeginBlockScope( + $"public void Serialize(ref Utf8YamlEmitter emitter, {returnType} value, YamlSerializationContext context)"); + + if (!typeMeta.Symbol.IsValueType) + { + using (codeWriter.BeginBlockScope("if (value is null)")) + { + codeWriter.AppendLine("emitter.WriteNull();"); + codeWriter.AppendLine("return;"); + } + } + + codeWriter.AppendLine("emitter.BeginMapping();"); + foreach (var memberMeta in memberMetas) + { + if (memberMeta.HasKeyNameAlias) + { + codeWriter.AppendLine($"emitter.WriteString(\"{memberMeta.KeyName}\");"); + } + else + { + codeWriter.AppendLine($"emitter.WriteString(\"{memberMeta.KeyName}\", ScalarStyle.Plain);"); + } + codeWriter.AppendLine($"context.Serialize(ref emitter, value.{memberMeta.Name});"); + } + codeWriter.AppendLine("emitter.EndMapping();"); + + return true; + } + + static bool TryEmitSerializeMethodUnion(TypeMeta typeMeta, CodeWriter codeWriter, in SourceProductionContext context) + { + var returnType = typeMeta.Symbol.IsValueType + ? typeMeta.FullTypeName + : $"{typeMeta.FullTypeName}?"; + + codeWriter.AppendLine("[VYaml.Annotations.Preserve]"); + using var methodScope = codeWriter.BeginBlockScope( + $"public void Serialize(ref Utf8YamlEmitter emitter, {returnType} value, YamlSerializationContext context)"); + + if (!typeMeta.Symbol.IsValueType) + { + using (codeWriter.BeginBlockScope("if (value is null)")) + { + codeWriter.AppendLine("emitter.WriteNull();"); + codeWriter.AppendLine("return;"); + } + } + + using (codeWriter.BeginBlockScope("switch (value)")) + { + foreach (var unionMeta in typeMeta.UnionMetas) + { + codeWriter.AppendLine($"case {unionMeta.FullTypeName} x:"); + codeWriter.AppendLine($" emitter.Tag(\"{unionMeta.SubTypeTag}\");"); + codeWriter.AppendLine($" context.Serialize(ref emitter, x);"); + codeWriter.AppendLine( " break;"); + } + } + return true; + } + + static bool TryEmitDeserializeMethod( + TypeMeta typeMeta, + CodeWriter codeWriter, + ReferenceSymbols references, + in SourceProductionContext context) + { + if (!TryGetConstructor(typeMeta, references, in context, + out var selectedConstructor, + out var constructedMembers)) + { + return false; + } + + var setterMembers = typeMeta.MemberMetas + .Where(x => + { + return constructedMembers.All(constructedMember => !SymbolEqualityComparer.Default.Equals(x.Symbol, constructedMember.Symbol)); + }) + .ToArray(); + + foreach (var setterMember in setterMembers) + { + switch (setterMember) + { + case { IsProperty: true, IsSettable: false }: + { + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.YamlMemberPropertyMustHaveSetter, + setterMember.GetLocation(typeMeta.Syntax), + typeMeta.TypeName, + setterMember.Name)); + return false; + } + case { IsField: true, IsSettable: false }: + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.YamlMemberFieldCannotBeReadonly, + setterMember.GetLocation(typeMeta.Syntax), + typeMeta.TypeName, + setterMember.Name)); + return false; + } + } + + var returnType = typeMeta.Symbol.IsValueType + ? typeMeta.FullTypeName + : $"{typeMeta.FullTypeName}?"; + codeWriter.AppendLine("[VYaml.Annotations.Preserve]"); + using var methodScope = codeWriter.BeginBlockScope( + $"public {returnType} Deserialize(ref YamlParser parser, YamlDeserializationContext context)"); + + using (codeWriter.BeginBlockScope("if (parser.IsNullScalar())")) + { + codeWriter.AppendLine("parser.Read();"); + codeWriter.AppendLine("return default;"); + } + + if (typeMeta.MemberMetas.Count <= 0) + { + codeWriter.AppendLine("parser.SkipCurrentNode();"); + codeWriter.AppendLine($"return new {typeMeta.TypeName}();"); + return true; + } + + codeWriter.AppendLine("parser.ReadWithVerify(ParseEventType.MappingStart);"); + codeWriter.AppendLine(); + foreach (var memberMeta in typeMeta.MemberMetas) + { + codeWriter.Append($"var __{memberMeta.Name}__ = "); + if (memberMeta.HasExplicitDefaultValueFromConstructor) + { + switch (memberMeta.ExplicitDefaultValueFromConstructor) + { + case null: + codeWriter.AppendLine("null;", false); + break; + case string stringValue: + codeWriter.AppendLine($"\"{stringValue}\";", false); + break; + case {} anyValue: + codeWriter.AppendLine($"{anyValue};", false); + break; + } + } + else + { + codeWriter.AppendLine($"default({memberMeta.FullTypeName});", false); + } + } + + using (codeWriter.BeginBlockScope("while (!parser.End && parser.CurrentEventType != ParseEventType.MappingEnd)")) + { + using (codeWriter.BeginBlockScope("if (parser.CurrentEventType != ParseEventType.Scalar)")) + { + codeWriter.AppendLine("throw new YamlSerializerException(parser.CurrentMark, \"Custom type deserialization supports only string key\");"); + } + codeWriter.AppendLine(); + using (codeWriter.BeginBlockScope("if (!parser.TryGetScalarAsSpan(out var key))")) + { + codeWriter.AppendLine("throw new YamlSerializerException(parser.CurrentMark, \"Custom type deserialization supports only string key\");"); + } + codeWriter.AppendLine(); + using (codeWriter.BeginBlockScope("switch (key.Length)")) + { + var membersByNameLength = typeMeta.MemberMetas.GroupBy(x => x.KeyNameUtf8Bytes.Length); + foreach (var group in membersByNameLength) + { + using (codeWriter.BeginIndentScope($"case {group.Key}:")) + { + var branching = "if"; + foreach (var memberMeta in group) + { + using (codeWriter.BeginBlockScope($"{branching} (key.SequenceEqual({memberMeta.Name}KeyUtf8Bytes))")) + { + codeWriter.AppendLine("parser.Read(); // skip key"); + codeWriter.AppendLine( + $"__{memberMeta.Name}__ = context.DeserializeWithAlias<{memberMeta.FullTypeName}>(ref parser);"); + } + branching = "else if"; + } + using (codeWriter.BeginBlockScope("else")) + { + codeWriter.AppendLine("parser.Read(); // skip key"); + codeWriter.AppendLine("parser.SkipCurrentNode(); // skip value"); + } + codeWriter.AppendLine("continue;"); + } + } + + using (codeWriter.BeginIndentScope("default:")) + { + codeWriter.AppendLine("parser.Read(); // skip key"); + codeWriter.AppendLine("parser.SkipCurrentNode(); // skip value"); + codeWriter.AppendLine("continue;"); + } + } + } + codeWriter.AppendLine("parser.ReadWithVerify(ParseEventType.MappingEnd);"); + + codeWriter.Append("return new "); + if (selectedConstructor != null) + { + var parameters = string.Join(",", constructedMembers.Select(x => + { + if (x.HasExplicitDefaultValueFromConstructor) + { + return x.ExplicitDefaultValueFromConstructor switch + { + null => $"__{x.Name}__ = null", + string stringValue => $"__{x.Name}__ = \"{stringValue}\"", + { } anyValue => $"__{x.Name}__ = {anyValue}" + }; + } + return $"__{x.Name}__"; + })); + codeWriter.Append($"{typeMeta.TypeName}({parameters})", false); + } + else + { + codeWriter.Append($"{typeMeta.TypeName}", false); + } + + if (setterMembers.Length > 0) + { + using (codeWriter.BeginBlockScope()) + { + foreach (var setterMember in setterMembers) + { + if (!constructedMembers.Contains(setterMember)) + { + codeWriter.AppendLine($"{setterMember.Name} = __{setterMember.Name}__,"); + } + } + } + } + codeWriter.AppendLine(";"); + return true; + } + + static bool TryEmitDeserializeMethodUnion(TypeMeta typeMeta, CodeWriter codeWriter, in SourceProductionContext context) + { + var returnType = typeMeta.Symbol.IsValueType + ? typeMeta.FullTypeName + : $"{typeMeta.FullTypeName}?"; + + codeWriter.AppendLine("[VYaml.Annotations.Preserve]"); + using var methodScope = codeWriter.BeginBlockScope( + $"public {returnType} Deserialize(ref YamlParser parser, YamlDeserializationContext context)"); + + using (codeWriter.BeginBlockScope("if (parser.IsNullScalar())")) + { + codeWriter.AppendLine("parser.Read();"); + codeWriter.AppendLine("return default;"); + } + + using (codeWriter.BeginBlockScope("if (!parser.TryGetCurrentTag(out var tag))")) + { + codeWriter.AppendLine("throw new YamlSerializerException(parser.CurrentMark, \"Cannot find any tag for union\");"); + } + + codeWriter.AppendLine(); + + var branch = "if"; + foreach (var unionMeta in typeMeta.UnionMetas) + { + using (codeWriter.BeginBlockScope($"{branch} (tag.Equals(\"{unionMeta.SubTypeTag}\")) ")) + { + codeWriter.AppendLine($"return context.DeserializeWithAlias<{unionMeta.FullTypeName}>(ref parser);"); + } + branch = "else if"; + } + using (codeWriter.BeginBlockScope("else")) + { + codeWriter.AppendLine("throw new YamlSerializerException(parser.CurrentMark, \"Cannot find any subtype tag for union\");"); + } + return true; + } + + static bool TryGetConstructor( + TypeMeta typeMeta, + ReferenceSymbols reference, + in SourceProductionContext context, + out IMethodSymbol? selectedConstructor, + out IReadOnlyList constructedMembers) + { + if (typeMeta.Constructors.Count <= 0) + { + selectedConstructor = null; + constructedMembers = Array.Empty(); + return true; + } + + if (typeMeta.Constructors.Count == 1) + { + selectedConstructor = typeMeta.Constructors[0]; + } + else + { + var ctorWithAttrs = typeMeta.Constructors + .Where(x => x.ContainsAttribute(reference.YamlConstructorAttribute)) + .ToArray(); + + switch (ctorWithAttrs.Length) + { + case 1: + selectedConstructor = ctorWithAttrs[0]; + break; + case > 1: + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.MultipleConstructorAttribute, + typeMeta.Syntax.Identifier.GetLocation(), + typeMeta.Symbol.Name)); + selectedConstructor = null; + constructedMembers = Array.Empty(); + return false; + + default: + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.MultipleConstructorWithoutAttribute, + typeMeta.Syntax.Identifier.GetLocation(), + typeMeta.Symbol.Name)); + selectedConstructor = null; + constructedMembers = Array.Empty(); + return false; + } + } + + var parameterMembers = new List(); + var error = false; + foreach (var parameter in selectedConstructor.Parameters) + { + var matchedMember = typeMeta.MemberMetas + .FirstOrDefault(member => parameter.Name.Equals(member.Name, StringComparison.OrdinalIgnoreCase)); + if (matchedMember != null) + { + matchedMember.IsConstructorParameter = true; + if (parameter.HasExplicitDefaultValue) + { + matchedMember.HasExplicitDefaultValueFromConstructor = true; + matchedMember.ExplicitDefaultValueFromConstructor = parameter.ExplicitDefaultValue; + } + parameterMembers.Add(matchedMember); + } + else + { + var location = selectedConstructor.Locations.FirstOrDefault() ?? + typeMeta.Syntax.Identifier.GetLocation(); + context.ReportDiagnostic(Diagnostic.Create( + DiagnosticDescriptors.ConstructorHasNoMatchedParameter, + location, + typeMeta.Symbol.Name, + parameter.Name)); + constructedMembers = Array.Empty(); + error = true; + } + } + constructedMembers = parameterMembers; + return !error; + } +} + + +class Comparer : IEqualityComparer<(GeneratorAttributeSyntaxContext, Compilation)> +{ + public static readonly Comparer Instance = new(); + + public bool Equals((GeneratorAttributeSyntaxContext, Compilation) x, (GeneratorAttributeSyntaxContext, Compilation) y) + { + return x.Item1.TargetNode.Equals(y.Item1.TargetNode); + } + + public int GetHashCode((GeneratorAttributeSyntaxContext, Compilation) obj) + { + return obj.Item1.TargetNode.GetHashCode(); + } +} \ No newline at end of file diff --git a/VYaml.Tests/Serialization/GeneratorDiagnosticsTest.cs b/VYaml.Tests/Serialization/GeneratorDiagnosticsTest.cs deleted file mode 100644 index 87c74af..0000000 --- a/VYaml.Tests/Serialization/GeneratorDiagnosticsTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -#if NET7_0_OR_GREATER -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using NUnit.Framework; -using VYaml.Annotations; -using VYaml.SourceGenerator; - -namespace VYaml.Tests -{ - [TestFixture] - public class GeneratorDiagnosticsTest - { - static Compilation baseCompilation = default!; - - static Compilation CreateCompilation(string source) - { - return CSharpCompilation.Create("compilation", - new[] { CSharpSyntaxTree.ParseText(source) }, - new[] - { - MetadataReference.CreateFromFile(typeof(YamlObjectUnionAttribute).Assembly.Location) - }, - new CSharpCompilationOptions(OutputKind.ConsoleApplication)); - } - - [Test] - [Ignore("Not passed")] - public void MuestBePartial() - { - var code = "using VYaml.Annotations\n" + - "\n" + - "[YamlObject]\n" + - "public class Hoge { }"; - - var inputCompilation = CreateCompilation(code); - - var driver = CSharpGeneratorDriver - .Create(new VYamlSourceGenerator()) - .RunGeneratorsAndUpdateCompilation( - inputCompilation, - out var outputCompilation, - out var diagnostics); - - Assert.That(diagnostics.Length, Is.EqualTo(1)); - } - } -} -#endif \ No newline at end of file diff --git a/VYaml.Tests/VYaml.Tests.csproj b/VYaml.Tests/VYaml.Tests.csproj index 7912dc9..f0fe824 100644 --- a/VYaml.Tests/VYaml.Tests.csproj +++ b/VYaml.Tests/VYaml.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 9 enable disable @@ -10,17 +10,18 @@ - + + - - + + Analyzer false diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest.meta b/VYaml.Unity/Assets/VYaml/PerformanceTest.meta new file mode 100644 index 0000000..c2741f9 --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/PerformanceTest.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5670ed606083f4514866017501069c3e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest/PerformanceTest.cs b/VYaml.Unity/Assets/VYaml/PerformanceTest/PerformanceTest.cs new file mode 100644 index 0000000..1585da6 --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/PerformanceTest/PerformanceTest.cs @@ -0,0 +1,119 @@ +using System.IO; +using System.Text; +using NUnit.Framework; +using Unity.PerformanceTesting; +using YamlDotNet.Serialization.NamingConventions; + +namespace VYaml.PerformanceTest +{ + public class PerformanceTest + { + const int N = 100; + + const string YAML = + "admin:\r\n address:\r\n socket_address: { address: 127.0.0.1, port_value: 9901 }\r\n\r\nstatic_resources:\r\n listeners:\r\n - name: listener_0\r\n address:\r\n socket_address: { address: 127.0.0.1, port_value: 10000 }\r\n filter_chains:\r\n - filters:\r\n - name: envoy.filters.network.http_connection_manager\r\n typed_config:\r\n \"@type\": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\r\n stat_prefix: ingress_http\r\n codec_type: AUTO\r\n route_config:\r\n name: local_route\r\n virtual_hosts:\r\n - name: local_service\r\n domains: [\"*\"]\r\n routes:\r\n - match: { prefix: \"/\" }\r\n route: { cluster: some_service }\r\n http_filters:\r\n - name: envoy.filters.http.router\r\n typed_config:\r\n \"@type\": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router\r\n clusters:\r\n - name: some_service\r\n connect_timeout: 0.25s\r\n lb_policy: ROUND_ROBIN\r\n type: EDS\r\n eds_cluster_config:\r\n eds_config:\r\n resource_api_version: V3\r\n api_config_source:\r\n api_type: GRPC\r\n transport_api_version: V3\r\n grpc_services:\r\n - envoy_grpc:\r\n cluster_name: xds_cluster\r\n - name: xds_cluster\r\n connect_timeout: 0.25s\r\n type: STATIC\r\n lb_policy: ROUND_ROBIN\r\n typed_extension_protocol_options:\r\n envoy.extensions.upstreams.http.v3.HttpProtocolOptions:\r\n \"@type\": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions\r\n explicit_http_config:\r\n http2_protocol_options:\r\n connection_keepalive:\r\n interval: 30s\r\n timeout: 5s\r\n upstream_connection_options:\r\n # configure a TCP keep-alive to detect and reconnect to the admin\r\n # server in the event of a TCP socket half open connection\r\n tcp_keepalive: {}\r\n load_assignment:\r\n cluster_name: xds_cluster\r\n endpoints:\r\n - lb_endpoints:\r\n - endpoint:\r\n address:\r\n socket_address:\r\n address: 127.0.0.1\r\n port_value: 5678"; + + [Test] + [Performance] + public void SimpleParsing() + { + var yamlBytes = Encoding.UTF8.GetBytes(YAML); + + Measure.Method(() => + { + var parser = VYaml.Parser.YamlParser.FromBytes(yamlBytes); + while (parser.Read()) + { + } + }) + .WarmupCount(5) + .IterationsPerMeasurement(N) + .MeasurementCount(20) + .GC() + .SampleGroup("VYaml.Parse") + .Run(); + + Measure.Method(() => + { + using var reader = new StringReader(YAML); + var parser = new YamlDotNet.Core.Parser(reader); + while (parser.MoveNext()) + { + } + }) + .WarmupCount(5) + .IterationsPerMeasurement(N) + .MeasurementCount(20) + .GC() + .SampleGroup("YamlDotNet.Parse") + .Run(); + } + + [Test] + [Performance] + public void DynamicDeserialize() + { + var yamlBytes = Encoding.UTF8.GetBytes(YAML); + var yamldotNetDeserializer = new YamlDotNet.Serialization.DeserializerBuilder() + .WithNamingConvention(CamelCaseNamingConvention.Instance) + .IgnoreUnmatchedProperties() + .Build(); + + Measure.Method(() => + { + VYaml.Serialization.YamlSerializer.Deserialize(yamlBytes); + }) + .WarmupCount(5) + .IterationsPerMeasurement(N) + .MeasurementCount(20) + .GC() + .SampleGroup("VYaml.Deserialize") + .Run(); + + Measure.Method(() => + { + yamldotNetDeserializer.Deserialize(YAML); + }) + .WarmupCount(5) + .IterationsPerMeasurement(N) + .MeasurementCount(20) + .GC() + .SampleGroup("YamlDotNet.Deserialize") + .Run(); + } + + [Test] + [Performance] + public void Deserialize() + { + var yamlBytes = Encoding.UTF8.GetBytes(YAML); + var yamldotNetDeserializer = new YamlDotNet.Serialization.DeserializerBuilder() + .WithNamingConvention(CamelCaseNamingConvention.Instance) + .IgnoreUnmatchedProperties() + .Build(); + + Measure.Method(() => + { + VYaml.Serialization.YamlSerializer.Deserialize(yamlBytes); + }) + .WarmupCount(5) + .IterationsPerMeasurement(N) + .MeasurementCount(20) + .GC() + .SampleGroup("VYaml.Deserialize") + .Run(); + + Measure.Method(() => + { + yamldotNetDeserializer.Deserialize(YAML); + }) + .WarmupCount(5) + .IterationsPerMeasurement(N) + .MeasurementCount(20) + .GC() + .SampleGroup("YamlDotNet.Deserialize") + .Run(); + } + + } +} diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest/PerformanceTest.cs.meta b/VYaml.Unity/Assets/VYaml/PerformanceTest/PerformanceTest.cs.meta new file mode 100644 index 0000000..1614267 --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/PerformanceTest/PerformanceTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 553ca8a4a74d745d2b244dbfe35f32aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs b/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs new file mode 100644 index 0000000..334741c --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; +using VYaml.Annotations; + +namespace VYaml.PerformanceTest +{ + [YamlObject] + public partial class TypedConfig + { + [YamlMember("@type")] + [YamlDotNet.Serialization.YamlMember(Alias = "@type")] + public string Type { get; set; } + + [YamlMember("stat_prefix")] + public string StatPrefix { get; set; } + + [YamlMember("codec_type")] + public string CodecType { get; set; } + + [YamlMember("route_config")] + public RouteConfig RouteConfig { get; set; } + } + + [YamlObject] + public partial class RouteConfig + {1 + public string Name { get; set; } + + [YamlMember("virtual_hosts")] + public List VirtualHosts { get; set; } + } + + [YamlObject] + public partial class Routes + { + public Dictionary Match { get; set; } + public Dictionary Route { get; set; } + } + + [YamlObject] + public partial class VirtualHost + { + public string Name { get; set; } + public List Domains { get; set; } + public List Routes { get; set; } + } + + [YamlObject] + public partial class SocketAddress + { + public string Address { get; set; } + + [YamlMember("port_value")] + public string PortValue { get; set; } + } + + [YamlObject] + public partial class Address + { + [YamlMember("socket_address")] + public SocketAddress SocketAddress { get; set; } + } + + [YamlObject] + public partial class Admin + { + public Address Address { get; set; } + } + + [YamlObject] + public partial class Listener + { + public string Name { get; set; } + public Address Address { get; set; } + + [YamlMember("filter_chains")] + public List FilterChains { get; set; } + } + + [YamlObject] + public partial class FilterChain + { + public List Filters { get; set; } + } + + [YamlObject] + public partial class Filter + { + public string Name { get; set; } + + [YamlMember("typed_config")] + public TypedConfig TypedConfig { get; set; } + + [YamlMember("http_filters")] + public List HttpFilters { get; set; } + } + + [YamlObject] + public partial class HttpFilter + { + public string Name { get; set; } + + [YamlMember("typed_config")] + public TypedConfig TypedConfig { get; set; } + } + + [YamlObject] + public partial class StaticResources + { + public List Listeners { get; set; } + } + + [YamlObject] + public partial class SampleEnvoy + { + public Admin Admin { get; set; } + + [YamlMember("static_resources")] + public StaticResources StaticResources { get; set; } + } +} \ No newline at end of file diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs.meta b/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs.meta new file mode 100644 index 0000000..8d09673 --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a51fbbfcbb0453ba59cd892880556b1 +timeCreated: 1670482681 \ No newline at end of file diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest/VYaml.PerformanceTest.asmdef b/VYaml.Unity/Assets/VYaml/PerformanceTest/VYaml.PerformanceTest.asmdef new file mode 100644 index 0000000..6163cfd --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/PerformanceTest/VYaml.PerformanceTest.asmdef @@ -0,0 +1,21 @@ +{ + "name": "VYaml.PerformanceTest", + "rootNamespace": "", + "references": [ + "GUID:7053a494724a448f18e88a849a83c098", + "GUID:c0dd0d10738d4ad4a9de57c559d0ca1b", + "GUID:27619889b8ba8c24980f49ee34dbb44a" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll", + "YamlDotNet.dll" + ], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest/VYaml.PerformanceTest.asmdef.meta b/VYaml.Unity/Assets/VYaml/PerformanceTest/VYaml.PerformanceTest.asmdef.meta new file mode 100644 index 0000000..dad5c88 --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/PerformanceTest/VYaml.PerformanceTest.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4a5597d8116194a0c8ad4ba1d934c4ce +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest/YamlDotNet.dll b/VYaml.Unity/Assets/VYaml/PerformanceTest/YamlDotNet.dll new file mode 100644 index 0000000000000000000000000000000000000000..ff6367b33ca9a5f08b4dfe71c21a03086ab06ef2 GIT binary patch literal 235520 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 b-O17a|KD#c1*W5-al1DE#!}!ndgA{NEheeL literal 0 HcmV?d00001 diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest/YamlDotNet.dll.meta b/VYaml.Unity/Assets/VYaml/PerformanceTest/YamlDotNet.dll.meta new file mode 100644 index 0000000..97b2c25 --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/PerformanceTest/YamlDotNet.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: a006ec9a3bebb4aa59b1c0455e3ac7f2 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/VYaml.Unity/Assets/VYaml/Runtime/VYaml.SourceGenerator.Roslyn3.dll b/VYaml.Unity/Assets/VYaml/Runtime/VYaml.SourceGenerator.Roslyn3.dll index 5a98ad298dab4e7dae150998efc93e5c7b635117..42457d38ed4143f9bc37f6a99adf9045aed910e0 100644 GIT binary patch delta 238 zcmZqp!PM}BX+j4};{3};H}Zf^(Bs%Dp_6h+CT%EPlbGk(88VVV-D` zm}X*@XknCQXklq)X=rL{oNQ!}Xq;$}l9p&`lx&n{ym`Zh9!8emL36H7cGwgk@NEM_ z@vf=6Jo_2r*SmbmR-U|IQ@sLIQ1d)g5TyEA;&eyLKgP?FB&F*&+i&h=@lRp^K???R zhC~JvAWj34WSlFN?n+LmERO zgBgPXg9#9uF<3Gf1EB?jIgo7*l(Pi0O&L-cQi1A{7>t0>guxKVHv{5Cpu8o6DNtt$ OkTzg2+$_E0DKh|8olZ3X diff --git a/VYaml.Unity/Assets/VYaml/Tests/Emitter/Utf8YamlEmitterTest.cs b/VYaml.Unity/Assets/VYaml/Tests/Emitter/Utf8YamlEmitterTest.cs index 84e4796..0b3cf05 100644 --- a/VYaml.Unity/Assets/VYaml/Tests/Emitter/Utf8YamlEmitterTest.cs +++ b/VYaml.Unity/Assets/VYaml/Tests/Emitter/Utf8YamlEmitterTest.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Buffers; using NUnit.Framework; using VYaml.Emitter; diff --git a/VYaml.Unity/Assets/VYaml/Tests/Parser/SpecTest.cs b/VYaml.Unity/Assets/VYaml/Tests/Parser/SpecTest.cs index af481fa..da9d44c 100644 --- a/VYaml.Unity/Assets/VYaml/Tests/Parser/SpecTest.cs +++ b/VYaml.Unity/Assets/VYaml/Tests/Parser/SpecTest.cs @@ -1,4 +1,3 @@ -#nullable enable using System; using System.Collections.Generic; using NUnit.Framework; diff --git a/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs b/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs index 87c74af..dcf46c5 100644 --- a/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs +++ b/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs @@ -1,48 +1,45 @@ -#if NET7_0_OR_GREATER +using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using NUnit; using NUnit.Framework; -using VYaml.Annotations; using VYaml.SourceGenerator; namespace VYaml.Tests { - [TestFixture] - public class GeneratorDiagnosticsTest - { - static Compilation baseCompilation = default!; - static Compilation CreateCompilation(string source) + public class GeneratorDIagnosticsTest + { + [Test] + public void MustBePartial() { - return CSharpCompilation.Create("compilation", - new[] { CSharpSyntaxTree.ParseText(source) }, - new[] - { - MetadataReference.CreateFromFile(typeof(YamlObjectUnionAttribute).Assembly.Location) - }, - new CSharpCompilationOptions(OutputKind.ConsoleApplication)); + var runResult = Generate(@" +[YamlObject] +class Hoge {} +"); + + var generatedFileSyntax = runResult.GeneratedTrees.Single(t => t.FilePath.EndsWith("Vector3.g.cs")); } - [Test] - [Ignore("Not passed")] - public void MuestBePartial() + static GeneratorDriverRunResult Generate(string code) { - var code = "using VYaml.Annotations\n" + - "\n" + - "[YamlObject]\n" + - "public class Hoge { }"; + // Create an instance of the source generator. + var generator = new VYamlIncrementalSourceGenerator(); - var inputCompilation = CreateCompilation(code); + // Source generators should be tested using 'GeneratorDriver'. + var driver = CSharpGeneratorDriver.Create(generator); - var driver = CSharpGeneratorDriver - .Create(new VYamlSourceGenerator()) - .RunGeneratorsAndUpdateCompilation( - inputCompilation, - out var outputCompilation, - out var diagnostics); + // We need to create a compilation with the required source code. + var compilation = CSharpCompilation.Create(nameof(GeneratorDIagnosticsTest), + new[] { CSharpSyntaxTree.ParseText(code) }, + new[] + { + // To support 'System.Attribute' inheritance, add reference to 'System.Private.CoreLib'. + MetadataReference.CreateFromFile(typeof(object).Assembly.Location) + }); - Assert.That(diagnostics.Length, Is.EqualTo(1)); + // Run generators and retrieve all results. + return driver.RunGenerators(compilation).GetRunResult(); } - } + } } -#endif \ No newline at end of file diff --git a/VYaml.Unity/ProjectSettings/ProjectSettings.asset b/VYaml.Unity/ProjectSettings/ProjectSettings.asset index 6846e29..2448aad 100644 --- a/VYaml.Unity/ProjectSettings/ProjectSettings.asset +++ b/VYaml.Unity/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 23 + serializedVersion: 27 productGUID: 126cba65ec895488ea5b72cdb0442d46 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -48,14 +48,16 @@ PlayerSettings: defaultScreenHeightWeb: 600 m_StereoRenderingPath: 0 m_ActiveColorSpace: 1 + unsupportedMSAAFallback: 0 + m_SpriteBatchVertexThreshold: 300 m_MTRendering: 1 mipStripping: 0 numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 iosUseCustomAppBackgroundBehavior: 0 - iosAllowHTTPDownload: 1 allowedAutorotateToPortrait: 1 allowedAutorotateToPortraitUpsideDown: 1 allowedAutorotateToLandscapeRight: 1 @@ -74,6 +76,7 @@ PlayerSettings: androidMinimumWindowWidth: 400 androidMinimumWindowHeight: 300 androidFullscreenMode: 1 + androidApplicationEntry: 1 defaultIsNativeResolution: 1 macRetinaSupport: 1 runInBackground: 1 @@ -85,6 +88,7 @@ PlayerSettings: hideHomeButton: 0 submitAnalytics: 1 usePlayerLog: 1 + dedicatedServerOptimizations: 0 bakeCollisionMeshes: 0 forceSingleInstance: 0 useFlipModelSwapchain: 1 @@ -92,6 +96,7 @@ PlayerSettings: useMacAppStoreValidation: 0 macAppStoreCategory: public.app-category.games gpuSkinning: 1 + meshDeformation: 2 xboxPIXTextureCapture: 0 xboxEnableAvatar: 0 xboxEnableKinect: 0 @@ -119,21 +124,18 @@ PlayerSettings: switchNVNShaderPoolsGranularity: 33554432 switchNVNDefaultPoolsGranularity: 16777216 switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 switchNVNMaxPublicTextureIDCount: 0 switchNVNMaxPublicSamplerIDCount: 0 - stadiaPresentMode: 0 - stadiaTargetFramerate: 0 + switchMaxWorkerMultiple: 8 + switchNVNGraphicsFirmwareMemory: 32 vulkanNumSwapchainBuffers: 3 vulkanEnableSetSRGBWrite: 0 vulkanEnablePreTransform: 1 vulkanEnableLateAcquireNextImage: 0 vulkanEnableCommandBufferRecycling: 1 - m_SupportedAspectRatios: - 4:3: 1 - 5:4: 1 - 16:10: 1 - 16:9: 1 - Others: 1 + loadStoreDebugModeEnabled: 0 bundleVersion: 0.1 preloadedAssets: [] metroInputSource: 0 @@ -146,8 +148,9 @@ PlayerSettings: isWsaHolographicRemotingEnabled: 0 enableFrameTimingStats: 0 enableOpenGLProfilerGPURecorders: 1 + allowHDRDisplaySupport: 0 useHDRDisplay: 0 - D3DHDRBitDepth: 0 + hdrBitDepth: 0 m_ColorGamuts: 00000000 targetPixelDensity: 30 resolutionScalingMode: 0 @@ -172,15 +175,16 @@ PlayerSettings: ForceInternetPermission: 0 ForceSDCardPermission: 0 CreateWallpaper: 0 - APKExpansionFiles: 0 + androidSplitApplicationBinary: 0 keepLoadedShadersAlive: 0 StripUnusedMeshComponents: 1 + strictShaderVariantMatching: 0 VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 - iOSTargetOSVersionString: 11.0 + iOSTargetOSVersionString: 13.0 tvOSSdkVersion: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 11.0 + tvOSTargetOSVersionString: 13.0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 @@ -244,6 +248,7 @@ PlayerSettings: useCustomLauncherGradleManifest: 0 useCustomBaseGradleTemplate: 0 useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 useCustomProguardFile: 0 AndroidTargetArchitectures: 1 AndroidTargetDevices: 0 @@ -251,6 +256,7 @@ PlayerSettings: androidSplashScreen: {fileID: 0} AndroidKeystoreName: AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 AndroidBuildApkPerCpuArchitecture: 0 AndroidTVCompatibility: 0 AndroidIsGame: 1 @@ -264,11 +270,11 @@ PlayerSettings: banner: {fileID: 0} androidGamepadSupportLevel: 0 chromeosInputEmulation: 1 - AndroidMinifyWithR8: 0 AndroidMinifyRelease: 0 AndroidMinifyDebug: 0 AndroidValidateAppBundleSize: 1 AndroidAppBundleSizeToValidate: 150 + AndroidReportGooglePlayAppDependencies: 1 m_BuildTargetIcons: [] m_BuildTargetPlatformIcons: [] m_BuildTargetBatching: @@ -350,6 +356,13 @@ PlayerSettings: iPhone: 1 tvOS: 1 m_BuildTargetGroupLightmapEncodingQuality: + - m_BuildTarget: Android + m_EncodingQuality: 1 + - m_BuildTarget: iPhone + m_EncodingQuality: 1 + - m_BuildTarget: tvOS + m_EncodingQuality: 1 + m_BuildTargetGroupHDRCubemapEncodingQuality: - m_BuildTarget: Android m_EncodingQuality: 1 - m_BuildTarget: iPhone @@ -357,6 +370,7 @@ PlayerSettings: - m_BuildTarget: tvOS m_EncodingQuality: 1 m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] m_BuildTargetNormalMapEncoding: - m_BuildTarget: Android m_Encoding: 1 @@ -365,8 +379,9 @@ PlayerSettings: - m_BuildTarget: tvOS m_Encoding: 1 m_BuildTargetDefaultTextureCompressionFormat: - - m_BuildTarget: Android - m_Format: 3 + - serializedVersion: 2 + m_BuildTarget: Android + m_Formats: 03000000 playModeTestRunnerEnabled: 0 runPlayModeTestAsEditModeTest: 0 actionOnDotNetUnhandledException: 1 @@ -377,6 +392,7 @@ PlayerSettings: locationUsageDescription: microphoneUsageDescription: bluetoothUsageDescription: + macOSTargetOSVersion: 10.13.0 switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 @@ -384,10 +400,12 @@ PlayerSettings: switchSocketConcurrencyLimit: 14 switchScreenResolutionBehavior: 2 switchUseCPUProfiler: 0 + switchEnableFileSystemTrace: 0 switchUseGOLDLinker: 0 switchLTOSetting: 0 switchApplicationID: 0x01004b9000490000 switchNSODependencies: + switchCompilerFlags: switchTitleNames_0: switchTitleNames_1: switchTitleNames_2: @@ -461,7 +479,6 @@ PlayerSettings: switchReleaseVersion: 0 switchDisplayVersion: 1.0.0 switchStartupUserAccount: 0 - switchTouchScreenUsage: 0 switchSupportedLanguagesMask: 0 switchLogoType: 0 switchApplicationErrorCodeCategory: @@ -503,6 +520,7 @@ PlayerSettings: switchNativeFsCacheSize: 32 switchIsHoldTypeHorizontal: 0 switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 switchSocketConfigEnabled: 0 switchTcpInitialSendBufferSize: 32 switchTcpInitialReceiveBufferSize: 64 @@ -513,7 +531,6 @@ PlayerSettings: switchSocketBufferEfficiency: 4 switchSocketInitializeEnabled: 1 switchNetworkInterfaceManagerInitializeEnabled: 1 - switchPlayerConnectionEnabled: 1 switchUseNewStyleFilepaths: 0 switchUseLegacyFmodPriorities: 1 switchUseMicroSleepForYield: 1 @@ -603,6 +620,7 @@ PlayerSettings: webGLMemorySize: 16 webGLExceptionSupport: 1 webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 webGLDataCaching: 1 webGLDebugSymbols: 0 webGLEmscriptenArgs: @@ -615,25 +633,45 @@ PlayerSettings: webGLLinkerTarget: 1 webGLThreadsSupport: 0 webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 webGLPowerPreference: 2 scriptingDefineSymbols: {} additionalCompilerArguments: {} platformArchitecture: {} - scriptingBackend: {} + scriptingBackend: + Android: 0 il2cppCompilerConfiguration: {} - managedStrippingLevel: {} + il2cppCodeGeneration: {} + il2cppStacktraceInformation: {} + managedStrippingLevel: + Android: 1 + EmbeddedLinux: 1 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + QNX: 1 + WebGL: 1 + Windows Store Apps: 1 + XboxOne: 1 + iPhone: 1 + tvOS: 1 incrementalIl2cppBuild: {} suppressCommonWarnings: 1 allowUnsafeCode: 0 useDeterministicCompilation: 1 - enableRoslynAnalyzers: 1 - selectedPlatform: 0 additionalIl2CppArgs: scriptingRuntimeVersion: 1 gcIncremental: 1 - assemblyVersionValidation: 1 gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: {} + editorAssembliesCompatibilityLevel: 1 m_RenderingPath: 1 m_MobileRenderingPath: 1 metroPackageName: Template_3D @@ -704,6 +742,11 @@ PlayerSettings: luminVersion: m_VersionCode: 1 m_VersionName: + hmiPlayerDataPath: + hmiForceSRGBBlit: 1 + embeddedLinuxEnableGamepadInput: 1 + hmiLogStartupTiming: 0 + hmiCpuConfiguration: apiCompatibilityLevel: 3 activeInputHandler: 0 windowsGamepadBackendHint: 0 @@ -714,6 +757,6 @@ PlayerSettings: organizationId: cloudEnabled: 0 legacyClampBlendShapeWeights: 0 - playerDataPath: - forceSRGBBlit: 1 + hmiLoadingImage: {fileID: 0} virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 diff --git a/VYaml.sln b/VYaml.sln index de414fd..7095577 100644 --- a/VYaml.sln +++ b/VYaml.sln @@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VYaml.Annotations", "VYaml. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VYaml", "VYaml\VYaml.csproj", "{376F0147-2997-4A8E-A147-FBAFD6B20818}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VYaml.SourceGenerator", "VYaml.SourceGenerator\VYaml.SourceGenerator.csproj", "{8C40A126-F956-41D4-87E8-03216E6B7891}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -42,5 +44,9 @@ Global {376F0147-2997-4A8E-A147-FBAFD6B20818}.Debug|Any CPU.Build.0 = Debug|Any CPU {376F0147-2997-4A8E-A147-FBAFD6B20818}.Release|Any CPU.ActiveCfg = Release|Any CPU {376F0147-2997-4A8E-A147-FBAFD6B20818}.Release|Any CPU.Build.0 = Release|Any CPU + {8C40A126-F956-41D4-87E8-03216E6B7891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C40A126-F956-41D4-87E8-03216E6B7891}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C40A126-F956-41D4-87E8-03216E6B7891}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C40A126-F956-41D4-87E8-03216E6B7891}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal From 919a6352385904efc226959b1f27cfae66fa9ad1 Mon Sep 17 00:00:00 2001 From: hadashiA Date: Sun, 10 Dec 2023 18:04:11 +0900 Subject: [PATCH 2/5] Update build settings --- Directory.Build.props | 1 + .../VYaml.SourceGenerator.Roslyn3.csproj | 25 ++---- .../VYaml.SourceGenerator.csproj | 17 ++++- .../Runtime/VYaml.SourceGenerator.Roslyn3.dll | Bin 48128 -> 0 bytes .../VYaml.SourceGenerator.Roslyn3.dll.meta | 71 ------------------ 5 files changed, 21 insertions(+), 93 deletions(-) delete mode 100644 VYaml.Unity/Assets/VYaml/Runtime/VYaml.SourceGenerator.Roslyn3.dll delete mode 100644 VYaml.Unity/Assets/VYaml/Runtime/VYaml.SourceGenerator.Roslyn3.dll.meta diff --git a/Directory.Build.props b/Directory.Build.props index 6454275..8eb3d69 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,5 +7,6 @@ $(PackageProjectUrl) git MIT + $(Version) diff --git a/VYaml.SourceGenerator.Roslyn3/VYaml.SourceGenerator.Roslyn3.csproj b/VYaml.SourceGenerator.Roslyn3/VYaml.SourceGenerator.Roslyn3.csproj index b1a43ce..8071836 100644 --- a/VYaml.SourceGenerator.Roslyn3/VYaml.SourceGenerator.Roslyn3.csproj +++ b/VYaml.SourceGenerator.Roslyn3/VYaml.SourceGenerator.Roslyn3.csproj @@ -1,16 +1,17 @@ netstandard2.0 + 12 enable enable + VYaml.SourceGenerator + cs false true true - $(TargetsForTfmSpecificContentInPackage);PackBuildOutputs - 11 - VYaml.SourceGenerator true + yaml Code generator for VYaml @@ -24,19 +25,7 @@ - - - $(MSBuildProjectDirectory)\..\VYaml.Unity\Assets\VYaml\Runtime - - - - - - - - - - - - + + + diff --git a/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj b/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj index e54b49f..1c3105c 100644 --- a/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj +++ b/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj @@ -1,16 +1,23 @@ - netstandard2.1 - false - enable 12 + enable + cs + false + true + false true + true true VYaml.SourceGenerator VYaml.SourceGenerator + + yaml + Code generator for VYaml + @@ -22,5 +29,7 @@ - + + + diff --git a/VYaml.Unity/Assets/VYaml/Runtime/VYaml.SourceGenerator.Roslyn3.dll b/VYaml.Unity/Assets/VYaml/Runtime/VYaml.SourceGenerator.Roslyn3.dll deleted file mode 100644 index 42457d38ed4143f9bc37f6a99adf9045aed910e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48128 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 z
    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 P{jZVu{|ovqYT*9?K0LSy diff --git a/VYaml.Unity/Assets/VYaml/Runtime/VYaml.SourceGenerator.Roslyn3.dll.meta b/VYaml.Unity/Assets/VYaml/Runtime/VYaml.SourceGenerator.Roslyn3.dll.meta deleted file mode 100644 index b297ec9..0000000 --- a/VYaml.Unity/Assets/VYaml/Runtime/VYaml.SourceGenerator.Roslyn3.dll.meta +++ /dev/null @@ -1,71 +0,0 @@ -fileFormatVersion: 2 -guid: 51de8dec1268a40f38a5c1036fadfa02 -labels: -- RoslynAnalyzer -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Editor: 1 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - Windows Store Apps: WindowsStoreApps - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: From b850bed4679dac787043df5fd340e91c43ea56a3 Mon Sep 17 00:00:00 2001 From: hadashiA Date: Sun, 10 Dec 2023 18:46:23 +0900 Subject: [PATCH 3/5] Fix warnings --- VYaml.SourceGenerator.Roslyn3/DiagnosticDescriptors.cs | 6 +++--- VYaml.SourceGenerator/DiagnosticDescriptors.cs | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/VYaml.SourceGenerator.Roslyn3/DiagnosticDescriptors.cs b/VYaml.SourceGenerator.Roslyn3/DiagnosticDescriptors.cs index b2c15f1..b95a267 100644 --- a/VYaml.SourceGenerator.Roslyn3/DiagnosticDescriptors.cs +++ b/VYaml.SourceGenerator.Roslyn3/DiagnosticDescriptors.cs @@ -32,8 +32,8 @@ static class DiagnosticDescriptors public static readonly DiagnosticDescriptor YamlMemberPropertyMustHaveSetter = new( id: "VYAML004", - title: "A yaml serializable property with must have setter.", - messageFormat: "The VYaml serializable object '{0}' property '{1}' must have setter.", + title: "A yaml serializable property with must have setter", + messageFormat: "The VYaml serializable object '{0}' property '{1}' must have setter", category: Category, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); @@ -41,7 +41,7 @@ static class DiagnosticDescriptors public static readonly DiagnosticDescriptor YamlMemberFieldCannotBeReadonly = new( id: "VYAML005", title: "A yaml serializable field cannot be readonly", - messageFormat: "The VYaml serializable object '{0}' field '{1}' cannot be readonly.", + messageFormat: "The VYaml serializable object '{0}' field '{1}' cannot be readonly", category: Category, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); diff --git a/VYaml.SourceGenerator/DiagnosticDescriptors.cs b/VYaml.SourceGenerator/DiagnosticDescriptors.cs index b2c15f1..3ebada4 100644 --- a/VYaml.SourceGenerator/DiagnosticDescriptors.cs +++ b/VYaml.SourceGenerator/DiagnosticDescriptors.cs @@ -1,3 +1,5 @@ +#pragma warning disable RS2008 + using Microsoft.CodeAnalysis; namespace VYaml.SourceGenerator; @@ -32,8 +34,8 @@ static class DiagnosticDescriptors public static readonly DiagnosticDescriptor YamlMemberPropertyMustHaveSetter = new( id: "VYAML004", - title: "A yaml serializable property with must have setter.", - messageFormat: "The VYaml serializable object '{0}' property '{1}' must have setter.", + title: "A yaml serializable property with must have setter", + messageFormat: "The VYaml serializable object '{0}' property '{1}' must have setter", category: Category, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); @@ -41,7 +43,7 @@ static class DiagnosticDescriptors public static readonly DiagnosticDescriptor YamlMemberFieldCannotBeReadonly = new( id: "VYAML005", title: "A yaml serializable field cannot be readonly", - messageFormat: "The VYaml serializable object '{0}' field '{1}' cannot be readonly.", + messageFormat: "The VYaml serializable object '{0}' field '{1}' cannot be readonly", category: Category, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); From 3fe7b46241139dfc0eef6e4e11b7f1fefed2fa2d Mon Sep 17 00:00:00 2001 From: hadashiA Date: Sun, 10 Dec 2023 19:06:24 +0900 Subject: [PATCH 4/5] Use netstandard2.0 --- VYaml.SourceGenerator/Shims/GlobalAliases.cs | 2 +- VYaml.SourceGenerator/Shims/Hash.cs | 26 +++++++++++ .../Shims/ImmutableArrayValueComparer.cs | 3 +- .../VYaml.SourceGenerator.csproj | 2 +- .../VYaml/PerformanceTest/SampleEnvoy.cs | 2 +- .../Serialization/GeneratorDiagnosticsTest.cs | 45 ------------------- .../GeneratorDiagnosticsTest.cs.meta | 11 ----- 7 files changed, 31 insertions(+), 60 deletions(-) create mode 100644 VYaml.SourceGenerator/Shims/Hash.cs delete mode 100644 VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs delete mode 100644 VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs.meta diff --git a/VYaml.SourceGenerator/Shims/GlobalAliases.cs b/VYaml.SourceGenerator/Shims/GlobalAliases.cs index ae7319d..6fa3476 100644 --- a/VYaml.SourceGenerator/Shims/GlobalAliases.cs +++ b/VYaml.SourceGenerator/Shims/GlobalAliases.cs @@ -49,7 +49,7 @@ public override int GetHashCode() { var hashCode = 0; foreach (var tuple in this.AliasAndSymbolNames) - hashCode = HashCode.Combine(tuple.GetHashCode(), hashCode); + hashCode = Hash.Combine(tuple.GetHashCode(), hashCode); _hashCode = hashCode == 0 ? 1 : hashCode; } diff --git a/VYaml.SourceGenerator/Shims/Hash.cs b/VYaml.SourceGenerator/Shims/Hash.cs new file mode 100644 index 0000000..4dd887a --- /dev/null +++ b/VYaml.SourceGenerator/Shims/Hash.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Copied from https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/Roslyn/Hash.cs + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; + +namespace Roslyn.Utilities +{ + internal static class Hash + { + /// + /// This is how VB Anonymous Types combine hash values for fields. + /// + internal static int Combine(int newKey, int currentKey) + { + return unchecked((currentKey * (int)0xA5555529) + newKey); + } + + // The rest of this file was removed as they were not currently needed in the polyfill of SyntaxValueProvider.ForAttributeWithMetadataName. + // If that changes, they should be added back as necessary. + } +} diff --git a/VYaml.SourceGenerator/Shims/ImmutableArrayValueComparer.cs b/VYaml.SourceGenerator/Shims/ImmutableArrayValueComparer.cs index 7c76832..c03764c 100644 --- a/VYaml.SourceGenerator/Shims/ImmutableArrayValueComparer.cs +++ b/VYaml.SourceGenerator/Shims/ImmutableArrayValueComparer.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions; @@ -23,7 +24,7 @@ public int GetHashCode(ImmutableArray obj) { var hashCode = 0; foreach (var value in obj) - hashCode = HashCode.Combine(hashCode, EqualityComparer.Default.GetHashCode(value!)); + hashCode = Hash.Combine(hashCode, EqualityComparer.Default.GetHashCode(value!)); return hashCode; } diff --git a/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj b/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj index 1c3105c..6bd4725 100644 --- a/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj +++ b/VYaml.SourceGenerator/VYaml.SourceGenerator.csproj @@ -1,6 +1,6 @@ - netstandard2.1 + netstandard2.0 12 enable diff --git a/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs b/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs index 334741c..dadaeea 100644 --- a/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs +++ b/VYaml.Unity/Assets/VYaml/PerformanceTest/SampleEnvoy.cs @@ -22,7 +22,7 @@ public partial class TypedConfig [YamlObject] public partial class RouteConfig - {1 + { public string Name { get; set; } [YamlMember("virtual_hosts")] diff --git a/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs b/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs deleted file mode 100644 index dcf46c5..0000000 --- a/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using NUnit; -using NUnit.Framework; -using VYaml.SourceGenerator; - -namespace VYaml.Tests -{ - - public class GeneratorDIagnosticsTest - { - [Test] - public void MustBePartial() - { - var runResult = Generate(@" -[YamlObject] -class Hoge {} -"); - - var generatedFileSyntax = runResult.GeneratedTrees.Single(t => t.FilePath.EndsWith("Vector3.g.cs")); - } - - static GeneratorDriverRunResult Generate(string code) - { - // Create an instance of the source generator. - var generator = new VYamlIncrementalSourceGenerator(); - - // Source generators should be tested using 'GeneratorDriver'. - var driver = CSharpGeneratorDriver.Create(generator); - - // We need to create a compilation with the required source code. - var compilation = CSharpCompilation.Create(nameof(GeneratorDIagnosticsTest), - new[] { CSharpSyntaxTree.ParseText(code) }, - new[] - { - // To support 'System.Attribute' inheritance, add reference to 'System.Private.CoreLib'. - MetadataReference.CreateFromFile(typeof(object).Assembly.Location) - }); - - // Run generators and retrieve all results. - return driver.RunGenerators(compilation).GetRunResult(); - } - } -} diff --git a/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs.meta b/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs.meta deleted file mode 100644 index b30f123..0000000 --- a/VYaml.Unity/Assets/VYaml/Tests/Serialization/GeneratorDiagnosticsTest.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d0d18d177685d42bd827aa33a9dc36c7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From 92fd8c0d7852cbfe811fb94a48069822c16ae31f Mon Sep 17 00:00:00 2001 From: hadashiA Date: Mon, 11 Dec 2023 09:25:09 +0900 Subject: [PATCH 5/5] CI --- .github/workflows/release.yaml | 7 +- .github/workflows/test.yaml | 2 +- Directory.Build.props | 1 - VYaml.Unity/Assets/VYaml/Runtime/Plugins.meta | 8 ++ .../Runtime/Plugins/VYaml.SourceGenerator.dll | Bin 0 -> 68096 bytes .../Plugins/VYaml.SourceGenerator.dll.meta | 72 ++++++++++++++++++ 6 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 VYaml.Unity/Assets/VYaml/Runtime/Plugins.meta create mode 100644 VYaml.Unity/Assets/VYaml/Runtime/Plugins/VYaml.SourceGenerator.dll create mode 100644 VYaml.Unity/Assets/VYaml/Runtime/Plugins/VYaml.SourceGenerator.dll.meta diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7436729..6044e41 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -10,7 +10,7 @@ on: default: false type: boolean jobs: - nuget-publish: + build-dotnet: runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -20,11 +20,12 @@ jobs: - uses: actions/setup-dotnet@v3 with: dotnet-version: | - 6.0.x + 8.0.x - run: dotnet build -c Release - run: dotnet test -c Release --no-build - run: dotnet pack -c Release --no-build -o ./publish - - run: rm ./publish/VYaml.Benchmark.* + - run: | + rm ./publish/VYaml.Benchmark.* - uses: actions/upload-artifact@v3 with: name: nuget diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 38cc1ca..e8ed643 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -18,6 +18,6 @@ jobs: - uses: actions/setup-dotnet@v3 with: dotnet-version: | - 6.0.x + 8.0.x - run: dotnet build -c Debug - run: dotnet test -c Debug --no-build diff --git a/Directory.Build.props b/Directory.Build.props index 8eb3d69..6454275 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,6 +7,5 @@ $(PackageProjectUrl) git MIT - $(Version) diff --git a/VYaml.Unity/Assets/VYaml/Runtime/Plugins.meta b/VYaml.Unity/Assets/VYaml/Runtime/Plugins.meta new file mode 100644 index 0000000..59e7a37 --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/Runtime/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cfb47aa8e4e2040e8828318164e26f1d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VYaml.Unity/Assets/VYaml/Runtime/Plugins/VYaml.SourceGenerator.dll b/VYaml.Unity/Assets/VYaml/Runtime/Plugins/VYaml.SourceGenerator.dll new file mode 100644 index 0000000000000000000000000000000000000000..94f73d03a675a279a52ad1865f4d01fc756c91c8 GIT binary patch literal 68096 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 DE`b#V literal 0 HcmV?d00001 diff --git a/VYaml.Unity/Assets/VYaml/Runtime/Plugins/VYaml.SourceGenerator.dll.meta b/VYaml.Unity/Assets/VYaml/Runtime/Plugins/VYaml.SourceGenerator.dll.meta new file mode 100644 index 0000000..54d7835 --- /dev/null +++ b/VYaml.Unity/Assets/VYaml/Runtime/Plugins/VYaml.SourceGenerator.dll.meta @@ -0,0 +1,72 @@ +fileFormatVersion: 2 +guid: 112e8fd6f837d416987df6f72eae23f9 +labels: +- RoslynAnalyzer +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 1 + validateReferences: 0 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: