From ac3958a0b87098ca5963ca12ab70383ff3b01b0d Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 31 May 2021 16:30:17 -0700 Subject: [PATCH] fix(codegen): Fixes codegen on VS2019 (#629) - [X] Fixes code gen on VS2019 - [X] Fixes schema generator not iterating through all nodes - [X] Fixes errors with building the actual code gen --- .../SerializableEntityGeneration.Class.cs | 94 ++++++++++++++++--- ...zableEntityGeneration.DeserializeMethod.cs | 5 +- .../Rules/ArrayMigrationRule.cs | 10 +- .../Rules/HashSetMigrationRule.cs | 8 +- .../Rules/ListMigrationRule.cs | 8 +- .../SerializableMigrationSchema.cs | 34 ++++++- .../SerializationGenerator.csproj | 4 +- .../SerializerSyntaxReceiver.cs | 2 +- .../Application.cs | 19 +++- .../SyntaxVisitor.cs | 3 + Projects/Server/Server.csproj | 24 +++-- Projects/UOContent/UOContent.csproj | 26 +++-- publish.cmd | 6 ++ 13 files changed, 198 insertions(+), 45 deletions(-) mode change 100644 => 100755 Projects/UOContent/UOContent.csproj diff --git a/Projects/SerializationGenerator/SerializableEntityGeneration/SerializableEntityGeneration.Class.cs b/Projects/SerializationGenerator/SerializableEntityGeneration/SerializableEntityGeneration.Class.cs index 5d0f4c445..8e088e5a8 100644 --- a/Projects/SerializationGenerator/SerializableEntityGeneration/SerializableEntityGeneration.Class.cs +++ b/Projects/SerializationGenerator/SerializableEntityGeneration/SerializableEntityGeneration.Class.cs @@ -13,9 +13,9 @@ * along with this program. If not, see . * *************************************************************************/ -using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; using System.Linq; using System.Text; using System.Text.Json; @@ -36,8 +36,66 @@ namespace SerializationGenerator ImmutableArray serializableTypes ) { - var compilation = context.Compilation; + var version = (int)serializableAttr.ConstructorArguments[0].Value!; + var migrations = context.GetMigrationsByAnalyzerConfig( + classSymbol, + version, + jsonSerializerOptions + ); + + return context.Compilation.GenerateSerializationPartialClass( + classSymbol, + serializableAttr, + null, // Do not generate schema + null, + migrations.ToImmutableArray(), + fieldsAndProperties, + serializableTypes + ); + } + + public static string GenerateSerializationPartialClass( + this Compilation compilation, + INamedTypeSymbol classSymbol, + AttributeData serializableAttr, + string? migrationPath, + JsonSerializerOptions? jsonSerializerOptions, + ImmutableArray fieldsAndProperties, + ImmutableArray serializableTypes + ) + { + var version = (int)serializableAttr.ConstructorArguments[0].Value!; + + var migrations = SerializableMigrationSchema.GetMigrations( + classSymbol, + version, + migrationPath, + jsonSerializerOptions + ); + + return compilation.GenerateSerializationPartialClass( + classSymbol, + serializableAttr, + migrationPath, + jsonSerializerOptions, + migrations.ToImmutableArray(), + fieldsAndProperties, + serializableTypes + ); + } + + public static string GenerateSerializationPartialClass( + this Compilation compilation, + INamedTypeSymbol classSymbol, + AttributeData serializableAttr, + string? migrationPath, + JsonSerializerOptions? jsonSerializerOptions, + ImmutableArray migrations, + ImmutableArray fieldsAndProperties, + ImmutableArray serializableTypes + ) + { var serializableFieldAttribute = compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_ATTRIBUTE); var serializableFieldAttrAttribute = @@ -120,7 +178,7 @@ namespace SerializationGenerator else { var attrType = (ITypeSymbol)attrTypeArg.Value; - source.GenerateAttribute(attrType.Name, ctorArgs[1].Values); + source.GenerateAttribute(attrType?.Name, ctorArgs[1].Values); } } @@ -172,17 +230,9 @@ namespace SerializationGenerator source.GenerateSerialCtor(compilation, className, isOverride); source.AppendLine(); - List migrations = new List(); - if (version > 0) { - migrations = context.GetMigrationsByAnalyzerConfig( - classSymbol, - version, - jsonSerializerOptions - ); - - for (var i = 0; i < migrations.Count; i++) + for (var i = 0; i < migrations.Length; i++) { var migration = migrations[i]; if (migration.Version < version) @@ -216,7 +266,27 @@ namespace SerializationGenerator source.GenerateClassEnd(); source.GenerateNamespaceEnd(); + if (migrationPath != null) + { + // Write the migration file + var newMigration = new SerializableMetadata + { + Version = version, + Type = classSymbol.ToDisplayString(), + Properties = serializableProperties + }; + + WriteMigration(migrationPath, newMigration, jsonSerializerOptions); + } + return source.ToString(); } + + private static void WriteMigration(string migrationPath, SerializableMetadata metadata, JsonSerializerOptions options) + { + Directory.CreateDirectory(migrationPath); + var filePath = Path.Combine(migrationPath, $"{metadata.Type}.v{metadata.Version}.json"); + File.WriteAllText(filePath, JsonSerializer.Serialize(metadata, options)); + } } } diff --git a/Projects/SerializationGenerator/SerializableEntityGeneration/SerializableEntityGeneration.DeserializeMethod.cs b/Projects/SerializationGenerator/SerializableEntityGeneration/SerializableEntityGeneration.DeserializeMethod.cs index 8ffd6a21f..497833442 100644 --- a/Projects/SerializationGenerator/SerializableEntityGeneration/SerializableEntityGeneration.DeserializeMethod.cs +++ b/Projects/SerializationGenerator/SerializableEntityGeneration/SerializableEntityGeneration.DeserializeMethod.cs @@ -13,7 +13,6 @@ * along with this program. If not, see . * *************************************************************************/ -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Text; @@ -32,7 +31,7 @@ namespace SerializationGenerator bool isOverride, int version, bool encodedVersion, - List migrations, + ImmutableArray migrations, ImmutableArray properties ) { @@ -61,7 +60,7 @@ namespace SerializationGenerator { var nextVersion = 0; - for (var i = 0; i < migrations.Count; i++) + for (var i = 0; i < migrations.Length; i++) { var migrationVersion = migrations[i].Version; if (migrationVersion == nextVersion) diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs index 542b767bf..ad8ece1c3 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs @@ -70,7 +70,7 @@ namespace SerializableMigration Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); var propertyIndex = $"{property.Name}Index"; - source.AppendLine($"{indent}{property.Name} = new {ruleArguments[0]}[reader.ReadInt()];"); + source.AppendLine($"{indent}{property.Name} = new {ruleArguments[0]}[reader.ReadEncodedInt()];"); source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {property.Name}.Length; {propertyIndex}++)"); source.AppendLine($"{indent}{{"); @@ -101,11 +101,9 @@ namespace SerializableMigration var arrayElementRuleArguments = new string[ruleArguments.Length - 2]; Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyIndex = $"{propertyVarPrefix}Index"; - source.AppendLine($"{indent}writer.Write({property.Name}.Length);"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyVarPrefix}.Length; {propertyIndex}++)"); + var propertyIndex = $"{property.Name}Index"; + source.AppendLine($"{indent}writer.WriteEncodedInt({property.Name}.Length);"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {property.Name}.Length; {propertyIndex}++)"); source.AppendLine($"{indent}{{"); var serializableArrayElement = new SerializableProperty diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs index 90dc538e0..96b8e7c4b 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs @@ -77,10 +77,12 @@ namespace SerializableMigration var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; var propertyIndex = $"{propertyVarPrefix}Index"; var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; source.AppendLine($"{indent}{ruleArguments[0]} {propertyEntry};"); - source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.HashSet<{ruleArguments[0]}>(reader.ReadInt());"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; i < {propertyName}.Count; {propertyIndex}++)"); + source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); + source.AppendLine($"{indent}{property.Name} = new System.Collections.Generic.HashSet<{ruleArguments[0]}>({propertyCount});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; i < {propertyCount}; {propertyIndex}++)"); source.AppendLine($"{indent}{{"); var serializableSetElement = new SerializableProperty @@ -114,7 +116,7 @@ namespace SerializableMigration var propertyName = property.Name; var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; var propertyEntry = $"{propertyVarPrefix}Entry"; - source.AppendLine($"{indent}writer.Write({property.Name}.Count);"); + source.AppendLine($"{indent}writer.WriteEncodedInt({property.Name}.Count);"); source.AppendLine($"{indent}foreach (var {propertyEntry} in {property.Name});"); source.AppendLine($"{indent}{{"); diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs index 7e6bda2ad..5ae28f411 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs @@ -77,10 +77,12 @@ namespace SerializableMigration var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; var propertyIndex = $"{propertyVarPrefix}Index"; var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; source.AppendLine($"{indent}{ruleArguments[0]} {propertyEntry};"); - source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.List<{ruleArguments[0]}>(reader.ReadInt());"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyName}.Count; {propertyIndex}++)"); + source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); + source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.List<{ruleArguments[0]}>({propertyCount});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); source.AppendLine($"{indent}{{"); var serializableListElement = new SerializableProperty @@ -113,7 +115,7 @@ namespace SerializableMigration var propertyName = property.Name; var propertyEntry = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}Entry"; - source.AppendLine($"{indent}writer.Write({propertyName}.Count);"); + source.AppendLine($"{indent}writer.WriteEncodedInt({propertyName}.Count);"); source.AppendLine($"{indent}foreach (var {propertyEntry} in {propertyName})"); source.AppendLine($"{indent}{{"); diff --git a/Projects/SerializationGenerator/SerializableMigration/SerializableMigrationSchema.cs b/Projects/SerializationGenerator/SerializableMigration/SerializableMigrationSchema.cs index deace7413..4465303a8 100644 --- a/Projects/SerializationGenerator/SerializableMigration/SerializableMigrationSchema.cs +++ b/Projects/SerializationGenerator/SerializableMigration/SerializableMigrationSchema.cs @@ -13,9 +13,11 @@ * along with this program. If not, see . * *************************************************************************/ +using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; @@ -35,7 +37,37 @@ namespace SerializableMigration private static Dictionary _cache = new(); - private static Regex _fileRegex = new(@"\S+\.v\d+\.json$"); + private static readonly Regex _fileRegex = new(@"\S+\.v\d+\.json$"); + + public static List GetMigrations( + INamedTypeSymbol typeSymbol, + int version, + string migrationPath, + JsonSerializerOptions options + ) + { + var typeName = typeSymbol.ToDisplayString(); + var migrations = new SortedSet(new SerializableMetadataComparer()); + + var migrationFiles = Directory.GetFiles(migrationPath, $"{typeName}.v*.json"); + + foreach (var file in migrationFiles) + { + var fi = new FileInfo(file); + if (!_cache.TryGetValue(fi.Name, out var migration)) + { + var text = File.ReadAllText(file, Encoding.UTF8); + migration = JsonSerializer.Deserialize(text, options); + } + + if (typeName == migration!.Type && version > migration.Version) + { + migrations.Add(migration); + } + } + + return migrations.ToList(); + } public static List GetMigrationsByAnalyzerConfig( this GeneratorExecutionContext context, diff --git a/Projects/SerializationGenerator/SerializationGenerator.csproj b/Projects/SerializationGenerator/SerializationGenerator.csproj index 2e69e3260..2ac66dd7c 100755 --- a/Projects/SerializationGenerator/SerializationGenerator.csproj +++ b/Projects/SerializationGenerator/SerializationGenerator.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 preview @@ -10,6 +10,7 @@ + @@ -20,6 +21,7 @@ + diff --git a/Projects/SerializationGenerator/SerializerSyntaxReceiver.cs b/Projects/SerializationGenerator/SerializerSyntaxReceiver.cs index cb471b80d..c38e7e0a7 100755 --- a/Projects/SerializationGenerator/SerializerSyntaxReceiver.cs +++ b/Projects/SerializationGenerator/SerializerSyntaxReceiver.cs @@ -13,9 +13,9 @@ * along with this program. If not, see . * *************************************************************************/ +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using SourceGeneration; diff --git a/Projects/SerializationSchemaGenerator/Application.cs b/Projects/SerializationSchemaGenerator/Application.cs index 59c3da884..4bbdcb884 100644 --- a/Projects/SerializationSchemaGenerator/Application.cs +++ b/Projects/SerializationSchemaGenerator/Application.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Immutable; using System.IO; +using System.Text; using System.Text.Json; using System.Threading.Tasks; using SerializationGenerator; @@ -44,7 +45,8 @@ namespace SerializationSchemaGenerator } var projectFile = new FileInfo(project.FilePath!); - var migrationPath = Path.Join(projectFile.Directory?.FullName, "Migrations"); + var projectPath = projectFile.Directory?.FullName; + var migrationPath = Path.Join(projectPath, "Migrations"); Directory.CreateDirectory(migrationPath); var syntaxReceiver = new SerializerSyntaxReceiver(); @@ -64,21 +66,32 @@ namespace SerializationSchemaGenerator ReadCommentHandling = JsonCommentHandling.Skip }; + // var generatedSourcePath = Path.Join(projectPath, "Generated"); + var serializableTypes = syntaxReceiver.SerializableList; foreach (var (classSymbol, (attributeData, fieldsList)) in syntaxReceiver.ClassAndFields) { - compilation.GenerateSchema( + var source = compilation.GenerateSerializationPartialClass( classSymbol, attributeData, - fieldsList.ToImmutableArray(), migrationPath, jsonOptions, + fieldsList.ToImmutableArray(), serializableTypes ); + + // WriteSource(generatedSourcePath, classSymbol.ToDisplayString(), source); } } ); } + + public static void WriteSource(string sourcePath, string className, string source) + { + Directory.CreateDirectory(sourcePath); + var filePath = Path.Combine(sourcePath, $"{className}.Serialization.cs"); + File.WriteAllText(filePath, source, Encoding.UTF8); + } } } diff --git a/Projects/SerializationSchemaGenerator/SyntaxVisitor.cs b/Projects/SerializationSchemaGenerator/SyntaxVisitor.cs index 9c645d271..1e47733be 100644 --- a/Projects/SerializationSchemaGenerator/SyntaxVisitor.cs +++ b/Projects/SerializationSchemaGenerator/SyntaxVisitor.cs @@ -33,16 +33,19 @@ namespace SerializationSchemaGenerator public override void VisitClassDeclaration(ClassDeclarationSyntax node) { + base.VisitClassDeclaration(node); _syntaxReceiver.OnVisitSyntaxNode(node, _semanticModel); } public override void VisitFieldDeclaration(FieldDeclarationSyntax node) { + base.VisitFieldDeclaration(node); _syntaxReceiver.OnVisitSyntaxNode(node, _semanticModel); } public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) { + base.VisitPropertyDeclaration(node); _syntaxReceiver.OnVisitSyntaxNode(node, _semanticModel); } } diff --git a/Projects/Server/Server.csproj b/Projects/Server/Server.csproj index 8ce4770b2..88f6fb600 100755 --- a/Projects/Server/Server.csproj +++ b/Projects/Server/Server.csproj @@ -14,6 +14,8 @@ Generated + + @@ -49,17 +51,27 @@ all + + + TargetFramework=netstandard2.0 + Analyzer + false + all + + + + + + + - - - - - - + + + diff --git a/Projects/UOContent/UOContent.csproj b/Projects/UOContent/UOContent.csproj old mode 100644 new mode 100755 index ee9ca2158..86258b188 --- a/Projects/UOContent/UOContent.csproj +++ b/Projects/UOContent/UOContent.csproj @@ -10,6 +10,8 @@ Generated + + @@ -39,13 +41,25 @@ + + + TargetFramework=netstandard2.0 + Analyzer + false + all + + + + + + + + + + + + - - - - - - diff --git a/publish.cmd b/publish.cmd index ffb855fff..140dd547c 100755 --- a/publish.cmd +++ b/publish.cmd @@ -27,11 +27,14 @@ if [[ $os == *'centos'* || $os == *'rhel'* ]]; then export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 fi +echo dotnet clean --verbosity quiet +dotnet clean --verbosity quiet echo dotnet restore --force-evaluate --source https://api.nuget.org/v3/index.json dotnet restore --force-evaluate --source https://api.nuget.org/v3/index.json echo dotnet publish ${config} ${os} --no-restore --self-contained=false -o Distribution/Assemblies Projects/UOContent/UOContent.csproj dotnet publish ${config} ${os} --no-restore --self-contained=false -o Distribution/Assemblies Projects/UOContent/UOContent.csproj + echo dotnet build -c Release Projects/SerializationSchemaGenerator/SerializationSchemaGenerator.csproj dotnet build -c Release Projects/SerializationSchemaGenerator/SerializationSchemaGenerator.csproj echo Generating serialization schemas @@ -57,11 +60,14 @@ IF "%~2" == "" ( SET os=-r %~2-x64 ) +echo dotnet clean --verbosity quiet +dotnet clean --verbosity quiet echo dotnet restore --force-evaluate --source https://api.nuget.org/v3/index.json dotnet restore --force-evaluate --source https://api.nuget.org/v3/index.json echo dotnet publish %config% %os% --no-restore --self-contained=false -o Distribution\Assemblies Projects\UOContent\UOContent.csproj dotnet publish %config% %os% --no-restore --self-contained=false -o Distribution\Assemblies Projects\UOContent\UOContent.csproj + echo dotnet build -c Release Projects/SerializationSchemaGenerator/SerializationSchemaGenerator.csproj dotnet build -c Release Projects/SerializationSchemaGenerator/SerializationSchemaGenerator.csproj echo Generating serialization schemas