fix: Moves codegen to its own repo (#918)
- [X] Replace serialization generator with nuget - [X] Replace schema migration with dotnet bool - [X] Add ability to run migrations in VS/Rider using a project build
This commit is contained in:
parent
01a41732f1
commit
48f1fe3384
56 changed files with 48 additions and 4727 deletions
12
.config/dotnet-tools.json
Normal file
12
.config/dotnet-tools.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"modernuoschemagenerator": {
|
||||
"version": "1.0.2",
|
||||
"commands": [
|
||||
"ModernUOSchemaGenerator"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Condition="!Exists('packages.config')">
|
||||
<Version>3.4.244</Version>
|
||||
<Version>3.4.255</Version>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<AdditionalFiles Include=".\Rules.ruleset" />
|
||||
|
|
|
|||
22
ModernUO.sln
22
ModernUO.sln
|
|
@ -12,9 +12,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UOContent.Tests", "Projects
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "Projects\Benchmarks\Benchmarks.csproj", "{38B7E4A1-FDDD-486C-98EE-BA7B13712528}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerializationGenerator", "Projects\SerializationGenerator\SerializationGenerator.csproj", "{07DDB8CF-F926-44F4-A584-FF2997D2C9D0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerializationSchemaGenerator", "Projects\SerializationSchemaGenerator\SerializationSchemaGenerator.csproj", "{A30150A3-796C-4C6D-B3E4-B7BEB0021701}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Run Schema Migrations", "Projects\Schema Migrations\Run Schema Migrations.csproj", "{75256276-FEAB-416C-9DB8-533FE816A0EF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
|
@ -53,18 +51,12 @@ Global
|
|||
{38B7E4A1-FDDD-486C-98EE-BA7B13712528}.Debug|x64.Build.0 = Debug|x64
|
||||
{38B7E4A1-FDDD-486C-98EE-BA7B13712528}.Release|x64.ActiveCfg = Release|x64
|
||||
{38B7E4A1-FDDD-486C-98EE-BA7B13712528}.Release|x64.Build.0 = Release|x64
|
||||
{07DDB8CF-F926-44F4-A584-FF2997D2C9D0}.Analyze|x64.ActiveCfg = Analyze|x64
|
||||
{07DDB8CF-F926-44F4-A584-FF2997D2C9D0}.Analyze|x64.Build.0 = Analyze|x64
|
||||
{07DDB8CF-F926-44F4-A584-FF2997D2C9D0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{07DDB8CF-F926-44F4-A584-FF2997D2C9D0}.Debug|x64.Build.0 = Debug|x64
|
||||
{07DDB8CF-F926-44F4-A584-FF2997D2C9D0}.Release|x64.ActiveCfg = Release|x64
|
||||
{07DDB8CF-F926-44F4-A584-FF2997D2C9D0}.Release|x64.Build.0 = Release|x64
|
||||
{A30150A3-796C-4C6D-B3E4-B7BEB0021701}.Analyze|x64.ActiveCfg = Analyze|x64
|
||||
{A30150A3-796C-4C6D-B3E4-B7BEB0021701}.Analyze|x64.Build.0 = Analyze|x64
|
||||
{A30150A3-796C-4C6D-B3E4-B7BEB0021701}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A30150A3-796C-4C6D-B3E4-B7BEB0021701}.Debug|x64.Build.0 = Debug|x64
|
||||
{A30150A3-796C-4C6D-B3E4-B7BEB0021701}.Release|x64.ActiveCfg = Release|x64
|
||||
{A30150A3-796C-4C6D-B3E4-B7BEB0021701}.Release|x64.Build.0 = Release|x64
|
||||
{75256276-FEAB-416C-9DB8-533FE816A0EF}.Analyze|x64.ActiveCfg = Analyze|x64
|
||||
{75256276-FEAB-416C-9DB8-533FE816A0EF}.Analyze|x64.Build.0 = Analyze|x64
|
||||
{75256276-FEAB-416C-9DB8-533FE816A0EF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{75256276-FEAB-416C-9DB8-533FE816A0EF}.Debug|x64.Build.0 = Debug|x64
|
||||
{75256276-FEAB-416C-9DB8-533FE816A0EF}.Release|x64.ActiveCfg = Release|x64
|
||||
{75256276-FEAB-416C-9DB8-533FE816A0EF}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
13
Projects/Schema Migrations/Run Schema Migrations.csproj
Normal file
13
Projects/Schema Migrations/Run Schema Migrations.csproj
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Schema_Migrations</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Target Name="Compile" />
|
||||
<Target Name="Build" />
|
||||
<Target Name="SchemaMigration" BeforeTargets="BeforeBuild">
|
||||
<Message Importance="High" Text="Installing schema generator tool" />
|
||||
<Exec Command="dotnet tool restore" />
|
||||
<Message Importance="High" Text="Generating migration schemas..." />
|
||||
<Exec Command="dotnet tool run ModernUOSchemaGenerator '$(ProjectDir)..\..\ModernUO.sln'" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: EntityJsonGenerator.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using SerializableMigration;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
[Generator]
|
||||
public class EntitySerializationGenerator : ISourceGenerator
|
||||
{
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterForSyntaxNotifications(() => new SerializerSyntaxReceiver());
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
if (context.SyntaxContextReceiver is not SerializerSyntaxReceiver receiver)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var jsonOptions = SerializableMigrationSchema.GetJsonSerializerOptions();
|
||||
// List of types that _will_ become ISerializable
|
||||
var serializableList = receiver.SerializableList;
|
||||
var embeddedSerializableList = receiver.EmbeddedSerializableList;
|
||||
|
||||
foreach (var (classSymbol, (serializableAttr, fieldsList)) in receiver.ClassAndFields)
|
||||
{
|
||||
if (serializableAttr == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string classSource = context.GenerateSerializationPartialClass(
|
||||
classSymbol,
|
||||
serializableAttr,
|
||||
false,
|
||||
fieldsList.ToImmutableArray(),
|
||||
jsonOptions,
|
||||
serializableList,
|
||||
embeddedSerializableList
|
||||
);
|
||||
|
||||
if (classSource != null)
|
||||
{
|
||||
context.AddSource($"{classSymbol.ToDisplayString()}.Serialization.cs", SourceText.From(classSource, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (classSymbol, (embeddedSerializableAttr, fieldsList)) in receiver.EmbeddedClassAndFields)
|
||||
{
|
||||
if (embeddedSerializableAttr == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string classSource = context.GenerateSerializationPartialClass(
|
||||
classSymbol,
|
||||
embeddedSerializableAttr,
|
||||
true,
|
||||
fieldsList.ToImmutableArray(),
|
||||
jsonOptions,
|
||||
serializableList,
|
||||
embeddedSerializableList
|
||||
);
|
||||
|
||||
if (classSource != null)
|
||||
{
|
||||
context.AddSource($"{classSymbol.ToDisplayString()}.Serialization.cs", SourceText.From(classSource, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
internal static class IsExternalInit {}
|
||||
}
|
||||
|
|
@ -1,436 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableEntityGeneration.Class.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializableMigration;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SerializableEntityGeneration
|
||||
{
|
||||
public static string GenerateSerializationPartialClass(
|
||||
this GeneratorExecutionContext context,
|
||||
INamedTypeSymbol classSymbol,
|
||||
AttributeData serializableAttr,
|
||||
bool embedded,
|
||||
ImmutableArray<ISymbol> fieldsAndProperties,
|
||||
JsonSerializerOptions jsonSerializerOptions,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes
|
||||
)
|
||||
{
|
||||
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
|
||||
embedded,
|
||||
null,
|
||||
migrations.ToImmutableArray(),
|
||||
fieldsAndProperties,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes
|
||||
);
|
||||
}
|
||||
|
||||
public static string GenerateSerializationPartialClass(
|
||||
this Compilation compilation,
|
||||
INamedTypeSymbol classSymbol,
|
||||
AttributeData serializableAttr,
|
||||
string? migrationPath,
|
||||
bool embedded,
|
||||
JsonSerializerOptions? jsonSerializerOptions,
|
||||
ImmutableArray<ISymbol> fieldsAndProperties,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes
|
||||
)
|
||||
{
|
||||
var version = (int)serializableAttr.ConstructorArguments[0].Value!;
|
||||
|
||||
var migrations = SerializableMigrationSchema.GetMigrations(
|
||||
classSymbol,
|
||||
version,
|
||||
migrationPath,
|
||||
jsonSerializerOptions
|
||||
);
|
||||
|
||||
return compilation.GenerateSerializationPartialClass(
|
||||
classSymbol,
|
||||
serializableAttr,
|
||||
migrationPath,
|
||||
embedded,
|
||||
jsonSerializerOptions,
|
||||
migrations.ToImmutableArray(),
|
||||
fieldsAndProperties,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes
|
||||
);
|
||||
}
|
||||
|
||||
public static string GenerateSerializationPartialClass(
|
||||
this Compilation compilation,
|
||||
INamedTypeSymbol classSymbol,
|
||||
AttributeData serializableAttr,
|
||||
string? migrationPath,
|
||||
bool embedded,
|
||||
JsonSerializerOptions? jsonSerializerOptions,
|
||||
ImmutableArray<SerializableMetadata> migrations,
|
||||
ImmutableArray<ISymbol> fieldsAndProperties,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes
|
||||
)
|
||||
{
|
||||
var serializableFieldAttribute =
|
||||
compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_ATTRIBUTE);
|
||||
var serializableFieldAttrAttribute =
|
||||
compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_ATTR_ATTRIBUTE);
|
||||
var serializableInterface =
|
||||
compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_INTERFACE);
|
||||
var parentSerializableAttribute =
|
||||
compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_PARENT_ATTRIBUTE);
|
||||
var serializableFieldSaveFlagAttribute =
|
||||
compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_SAVE_FLAG_ATTRIBUTE);
|
||||
var serializableFieldDefaultAttribute =
|
||||
compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_DEFAULT_ATTRIBUTE);
|
||||
|
||||
// If we have a parent that is or derives from ISerializable, then we are in override
|
||||
var isOverride = classSymbol.BaseType.ContainsInterface(serializableInterface);
|
||||
|
||||
if (!(embedded || isOverride || classSymbol.ContainsInterface(serializableInterface)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var isRawSerializable = classSymbol.HasRawSerializableInterface(compilation, ImmutableArray<INamedTypeSymbol>.Empty);
|
||||
|
||||
var version = (int)serializableAttr.ConstructorArguments[0].Value!;
|
||||
var encodedVersion = (bool)serializableAttr.ConstructorArguments[1].Value!;
|
||||
|
||||
// Let's find out if we need to do serialization flags
|
||||
var serializableFieldSaveFlags = new SortedDictionary<int, SerializableFieldSaveFlagMethods>();
|
||||
foreach (var m in classSymbol.GetMembers().OfType<IMethodSymbol>())
|
||||
{
|
||||
var getSaveFlagAttribute = m.GetAttribute(serializableFieldSaveFlagAttribute);
|
||||
var getDefaultValueAttribute = m.GetAttribute(serializableFieldDefaultAttribute);
|
||||
|
||||
if (getSaveFlagAttribute == null && getDefaultValueAttribute == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var attrCtorArgs = getSaveFlagAttribute?.ConstructorArguments ?? getDefaultValueAttribute.ConstructorArguments;
|
||||
var order = (int)attrCtorArgs[0].Value!;
|
||||
|
||||
serializableFieldSaveFlags.TryGetValue(order, out var saveFlagMethods);
|
||||
|
||||
serializableFieldSaveFlags[order] = new SerializableFieldSaveFlagMethods
|
||||
{
|
||||
DetermineFieldShouldSerialize = getSaveFlagAttribute != null ? m : saveFlagMethods?.DetermineFieldShouldSerialize,
|
||||
GetFieldDefaultValue = getDefaultValueAttribute != null ? m : saveFlagMethods?.GetFieldDefaultValue
|
||||
};
|
||||
}
|
||||
|
||||
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
||||
var className = classSymbol.Name;
|
||||
|
||||
StringBuilder source = new StringBuilder();
|
||||
|
||||
source.AppendLine("#pragma warning disable\n");
|
||||
source.GenerateNamespaceStart(namespaceName);
|
||||
|
||||
var interfaces = !embedded || isRawSerializable
|
||||
? Array.Empty<ITypeSymbol>()
|
||||
: new ITypeSymbol[] { compilation.GetTypeByMetadataName(SymbolMetadata.RAW_SERIALIZABLE_INTERFACE) };
|
||||
|
||||
var indent = " ";
|
||||
|
||||
source.RecursiveGenerateClassStart(classSymbol, interfaces.ToImmutableArray(), ref indent);
|
||||
|
||||
source.GenerateClassField(
|
||||
indent,
|
||||
Accessibility.Private,
|
||||
InstanceModifier.Const,
|
||||
"int",
|
||||
"_version",
|
||||
version.ToString()
|
||||
);
|
||||
source.AppendLine();
|
||||
|
||||
var parentFieldOrProperty = embedded ? fieldsAndProperties.FirstOrDefault(
|
||||
fieldOrPropertySymbol => fieldOrPropertySymbol.GetAttributes()
|
||||
.FirstOrDefault(
|
||||
attr =>
|
||||
SymbolEqualityComparer.Default.Equals(attr.AttributeClass, parentSerializableAttribute)
|
||||
) != null
|
||||
) : null;
|
||||
|
||||
var serializablePropertySet = new SortedDictionary<SerializableProperty, ISymbol>(new SerializablePropertyComparer());
|
||||
|
||||
foreach (var fieldOrPropertySymbol in fieldsAndProperties)
|
||||
{
|
||||
var allAttributes = fieldOrPropertySymbol.GetAttributes();
|
||||
|
||||
var serializableFieldAttr = allAttributes
|
||||
.FirstOrDefault(
|
||||
attr =>
|
||||
SymbolEqualityComparer.Default.Equals(attr.AttributeClass, serializableFieldAttribute)
|
||||
);
|
||||
|
||||
if (serializableFieldAttr == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var attr in allAttributes)
|
||||
{
|
||||
if (!SymbolEqualityComparer.Default.Equals(attr.AttributeClass, serializableFieldAttrAttribute))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attr.AttributeClass == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var ctorArgs = attr.ConstructorArguments;
|
||||
var attrTypeArg = ctorArgs[0];
|
||||
|
||||
if (attrTypeArg.Kind == TypedConstantKind.Primitive && attrTypeArg.Value is string attrStr)
|
||||
{
|
||||
source.AppendLine($"{indent}{attrStr}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var attrType = (ITypeSymbol)attrTypeArg.Value;
|
||||
source.GenerateAttribute(indent, attrType?.Name, ctorArgs[1].Values);
|
||||
}
|
||||
}
|
||||
|
||||
var attrCtorArgs = serializableFieldAttr.ConstructorArguments;
|
||||
|
||||
var order = (int)attrCtorArgs[0].Value!;
|
||||
var getterAccessor = Helpers.GetAccessibility(attrCtorArgs[1].Value?.ToString());
|
||||
var setterAccessor = Helpers.GetAccessibility(attrCtorArgs[2].Value?.ToString());
|
||||
var virtualProperty = (bool)attrCtorArgs[3].Value!;
|
||||
|
||||
if (fieldOrPropertySymbol is IFieldSymbol fieldSymbol)
|
||||
{
|
||||
source.GenerateSerializableProperty(
|
||||
compilation,
|
||||
indent,
|
||||
fieldSymbol,
|
||||
getterAccessor,
|
||||
setterAccessor,
|
||||
virtualProperty,
|
||||
parentFieldOrProperty
|
||||
);
|
||||
source.AppendLine();
|
||||
}
|
||||
|
||||
serializableFieldSaveFlags.TryGetValue(order, out var serializableFieldSaveFlagMethods);
|
||||
|
||||
var serializableProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
fieldOrPropertySymbol,
|
||||
order,
|
||||
allAttributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
classSymbol,
|
||||
serializableFieldSaveFlagMethods
|
||||
);
|
||||
|
||||
serializablePropertySet.Add(serializableProperty, fieldOrPropertySymbol);
|
||||
}
|
||||
|
||||
var serializableFields = serializablePropertySet.Keys.ToImmutableArray();
|
||||
var serializableProperties = serializablePropertySet.Select(
|
||||
kvp => kvp.Key with
|
||||
{
|
||||
Name = (kvp.Value as IFieldSymbol)?.GetPropertyName() ?? ((IPropertySymbol)kvp.Value).Name
|
||||
}
|
||||
).ToImmutableArray();
|
||||
|
||||
// If we are not inheriting ISerializable, then we need to define some stuff
|
||||
if (!(isOverride || embedded))
|
||||
{
|
||||
// long ISerializable.SavePosition { get; set; } = -1;
|
||||
source.GenerateAutoProperty(
|
||||
Accessibility.NotApplicable,
|
||||
"long",
|
||||
"ISerializable.SavePosition",
|
||||
Accessibility.NotApplicable,
|
||||
Accessibility.NotApplicable,
|
||||
indent,
|
||||
defaultValue: "-1"
|
||||
);
|
||||
|
||||
// BufferWriter ISerializable.SaveBuffer { get; set; }
|
||||
source.GenerateAutoProperty(
|
||||
Accessibility.NotApplicable,
|
||||
"BufferWriter",
|
||||
"ISerializable.SaveBuffer",
|
||||
Accessibility.NotApplicable,
|
||||
Accessibility.NotApplicable,
|
||||
indent
|
||||
);
|
||||
}
|
||||
|
||||
if (!embedded)
|
||||
{
|
||||
// Serial constructor
|
||||
source.GenerateSerialCtor(compilation, className, indent, isOverride);
|
||||
source.AppendLine();
|
||||
}
|
||||
|
||||
if (version > 0)
|
||||
{
|
||||
for (var i = 0; i < migrations.Length; i++)
|
||||
{
|
||||
var migration = migrations[i];
|
||||
if (migration.Version < version)
|
||||
{
|
||||
source.GenerateMigrationContentStruct(compilation, indent, migration, classSymbol);
|
||||
source.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize Method
|
||||
source.GenerateSerializeMethod(
|
||||
compilation,
|
||||
indent,
|
||||
isOverride,
|
||||
encodedVersion,
|
||||
serializableFields,
|
||||
serializableProperties,
|
||||
serializableFieldSaveFlags
|
||||
);
|
||||
source.AppendLine();
|
||||
|
||||
// Deserialize Method
|
||||
source.GenerateDeserializeMethod(
|
||||
compilation,
|
||||
classSymbol,
|
||||
indent,
|
||||
isOverride,
|
||||
version,
|
||||
encodedVersion,
|
||||
migrations,
|
||||
serializableFields,
|
||||
serializableProperties,
|
||||
parentFieldOrProperty,
|
||||
serializableFieldSaveFlags
|
||||
);
|
||||
|
||||
// Serialize SaveFlag enum class
|
||||
if (serializableFieldSaveFlags.Count > 0)
|
||||
{
|
||||
source.AppendLine();
|
||||
source.GenerateEnumStart(
|
||||
"SaveFlag",
|
||||
$"{indent} ",
|
||||
true,
|
||||
Accessibility.Private
|
||||
);
|
||||
|
||||
source.GenerateEnumValue($"{indent} ", true, "None", -1);
|
||||
int index = 0;
|
||||
foreach (var (order, _) in serializableFieldSaveFlags)
|
||||
{
|
||||
source.GenerateEnumValue($"{indent} ", true, serializableProperties[order].Name, index++);
|
||||
}
|
||||
|
||||
source.GenerateEnumEnd($"{indent} ");
|
||||
}
|
||||
|
||||
source.RecursiveGenerateClassEnd(classSymbol, ref indent);
|
||||
source.GenerateNamespaceEnd();
|
||||
|
||||
if (migrationPath != null)
|
||||
{
|
||||
// Write the migration file
|
||||
var newMigration = new SerializableMetadata
|
||||
{
|
||||
Version = version,
|
||||
Type = classSymbol.ToDisplayString(),
|
||||
Properties = serializableProperties.Length > 0 ? serializableProperties : null
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
private static void RecursiveGenerateClassStart(
|
||||
this StringBuilder source,
|
||||
INamedTypeSymbol classSymbol,
|
||||
ImmutableArray<ITypeSymbol> interfaces,
|
||||
ref string indent
|
||||
)
|
||||
{
|
||||
var containingSymbolList = new List<INamedTypeSymbol>();
|
||||
|
||||
do
|
||||
{
|
||||
containingSymbolList.Add(classSymbol);
|
||||
classSymbol = classSymbol.ContainingSymbol as INamedTypeSymbol;
|
||||
} while (classSymbol != null);
|
||||
|
||||
containingSymbolList.Reverse();
|
||||
|
||||
for (var i = 0; i < containingSymbolList.Count; i++)
|
||||
{
|
||||
var symbol = containingSymbolList[i];
|
||||
source.GenerateClassStart(symbol, indent, i == containingSymbolList.Count - 1 ? interfaces : ImmutableArray<ITypeSymbol>.Empty);
|
||||
indent += " ";
|
||||
}
|
||||
}
|
||||
|
||||
private static void RecursiveGenerateClassEnd(this StringBuilder source, INamedTypeSymbol classSymbol, ref string indent)
|
||||
{
|
||||
do
|
||||
{
|
||||
indent = indent.Substring(0, indent.Length - 4);
|
||||
source.GenerateClassEnd(indent);
|
||||
|
||||
classSymbol = classSymbol.ContainingSymbol as INamedTypeSymbol;
|
||||
} while (classSymbol != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableEntityGeneration.DeserializeMethod.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializableMigration;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SerializableEntityGeneration
|
||||
{
|
||||
public static void GenerateDeserializeMethod(
|
||||
this StringBuilder source,
|
||||
Compilation compilation,
|
||||
INamedTypeSymbol classSymbol,
|
||||
string indent,
|
||||
bool isOverride,
|
||||
int version,
|
||||
bool encodedVersion,
|
||||
ImmutableArray<SerializableMetadata> migrations,
|
||||
ImmutableArray<SerializableProperty> fields,
|
||||
ImmutableArray<SerializableProperty> properties,
|
||||
ISymbol parentFieldOrProperty,
|
||||
SortedDictionary<int, SerializableFieldSaveFlagMethods> serializableFieldSaveFlagMethodsDictionary
|
||||
)
|
||||
{
|
||||
var genericReaderInterface = compilation.GetTypeByMetadataName(SymbolMetadata.GENERIC_READER_INTERFACE);
|
||||
|
||||
source.GenerateMethodStart(
|
||||
indent,
|
||||
"Deserialize",
|
||||
Accessibility.Public,
|
||||
isOverride,
|
||||
"void",
|
||||
ImmutableArray.Create<(ITypeSymbol, string)>((genericReaderInterface, "reader"))
|
||||
);
|
||||
|
||||
var bodyIndent = $"{indent} ";
|
||||
var innerIndent = $"{bodyIndent} ";
|
||||
|
||||
if (isOverride)
|
||||
{
|
||||
source.AppendLine($"{bodyIndent}base.Deserialize(reader);");
|
||||
source.AppendLine();
|
||||
}
|
||||
|
||||
var afterDeserialization = classSymbol
|
||||
.GetMembers()
|
||||
.OfType<IMethodSymbol>()
|
||||
.Select(
|
||||
m =>
|
||||
{
|
||||
if (!m.ReturnsVoid || m.Parameters.Length != 0)
|
||||
{
|
||||
return (m, null);
|
||||
}
|
||||
|
||||
return (m, m.GetAttributes()
|
||||
.FirstOrDefault(
|
||||
attr => SymbolEqualityComparer.Default.Equals(
|
||||
attr.AttributeClass,
|
||||
compilation.GetTypeByMetadataName(SymbolMetadata.AFTERDESERIALIZATION_ATTRIBUTE)
|
||||
)
|
||||
));
|
||||
}
|
||||
).Where(m => m.Item2 != null).ToList();
|
||||
|
||||
// Version
|
||||
source.AppendLine($"{bodyIndent}var version = reader.{(encodedVersion ? "ReadEncodedInt" : "ReadInt")}();");
|
||||
|
||||
if (version > 0)
|
||||
{
|
||||
var parent = parentFieldOrProperty?.Name ?? "this";
|
||||
var nextVersion = 0;
|
||||
|
||||
for (var i = 0; i < migrations.Length; i++)
|
||||
{
|
||||
var migrationVersion = migrations[i].Version;
|
||||
if (migrationVersion == nextVersion)
|
||||
{
|
||||
nextVersion++;
|
||||
}
|
||||
|
||||
source.AppendLine();
|
||||
source.AppendLine($"{bodyIndent}if (version == {migrationVersion})");
|
||||
source.AppendLine($"{bodyIndent}{{");
|
||||
source.AppendLine($"{bodyIndent} MigrateFrom(new V{migrationVersion}Content(reader, this));");
|
||||
source.AppendLine($"{bodyIndent} {parent}.MarkDirty();");
|
||||
source.GenerateAfterDeserialization($"{bodyIndent} ", afterDeserialization);
|
||||
source.AppendLine($"{bodyIndent} return;");
|
||||
source.AppendLine($"{bodyIndent}}}");
|
||||
}
|
||||
|
||||
if (nextVersion < version)
|
||||
{
|
||||
source.AppendLine();
|
||||
source.AppendLine($"{bodyIndent}if (version < _version)");
|
||||
source.AppendLine($"{bodyIndent}{{");
|
||||
source.AppendLine($"{bodyIndent} Deserialize(reader, version);");
|
||||
source.AppendLine($"{bodyIndent} {parent}.MarkDirty();");
|
||||
source.GenerateAfterDeserialization($"{bodyIndent} ", afterDeserialization);
|
||||
source.AppendLine($"{bodyIndent} return;");
|
||||
source.AppendLine($"{bodyIndent}}}");
|
||||
}
|
||||
}
|
||||
|
||||
if (serializableFieldSaveFlagMethodsDictionary.Count > 0)
|
||||
{
|
||||
source.AppendLine();
|
||||
source.AppendLine($"{bodyIndent}var saveFlags = reader.ReadEnum<SaveFlag>();");
|
||||
}
|
||||
|
||||
for (var i = 0; i < properties.Length; i++)
|
||||
{
|
||||
var field = fields[i];
|
||||
var property = properties[i];
|
||||
var rule = SerializableMigrationRulesEngine.Rules[property.Rule];
|
||||
|
||||
if (serializableFieldSaveFlagMethodsDictionary.TryGetValue(
|
||||
property.Order,
|
||||
out var serializableFieldSaveFlagMethods
|
||||
))
|
||||
{
|
||||
source.AppendLine();
|
||||
// Special case
|
||||
if (property.Type == "bool")
|
||||
{
|
||||
source.AppendLine($"{bodyIndent}{field.Name} = (saveFlags & SaveFlag.{property.Name}) != 0;");
|
||||
}
|
||||
else
|
||||
{
|
||||
source.AppendLine($"{bodyIndent}if ((saveFlags & SaveFlag.{property.Name}) != 0)\n{bodyIndent}{{");
|
||||
rule.GenerateDeserializationMethod(
|
||||
source,
|
||||
innerIndent,
|
||||
field,
|
||||
parentFieldOrProperty?.Name ?? "this"
|
||||
);
|
||||
(rule as IPostDeserializeMethod)?.PostDeserializeMethod(
|
||||
source,
|
||||
innerIndent,
|
||||
field,
|
||||
compilation,
|
||||
classSymbol
|
||||
);
|
||||
|
||||
if (serializableFieldSaveFlagMethods.GetFieldDefaultValue != null)
|
||||
{
|
||||
source.AppendLine($"{bodyIndent}}}\n{bodyIndent}else\n{bodyIndent}{{");
|
||||
source.AppendLine(
|
||||
$"{bodyIndent} {field.Name} = {serializableFieldSaveFlagMethods.GetFieldDefaultValue.Name}();"
|
||||
);
|
||||
}
|
||||
|
||||
source.AppendLine($"{bodyIndent}}}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
source.AppendLine();
|
||||
rule.GenerateDeserializationMethod(
|
||||
source,
|
||||
bodyIndent,
|
||||
field,
|
||||
parentFieldOrProperty?.Name ?? "this"
|
||||
);
|
||||
(rule as IPostDeserializeMethod)?.PostDeserializeMethod(
|
||||
source,
|
||||
bodyIndent,
|
||||
field,
|
||||
compilation,
|
||||
classSymbol
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
source.GenerateAfterDeserialization($"{bodyIndent}", afterDeserialization);
|
||||
source.GenerateMethodEnd(indent);
|
||||
}
|
||||
|
||||
private static void GenerateAfterDeserialization(
|
||||
this StringBuilder source, string indent, IList<(IMethodSymbol, AttributeData?)> afterDeserialization
|
||||
)
|
||||
{
|
||||
foreach (var (method, attr) in afterDeserialization)
|
||||
{
|
||||
if ((bool)attr.ConstructorArguments[0].Value!)
|
||||
{
|
||||
source.AppendLine($"{indent}{method.Name}();");
|
||||
}
|
||||
else
|
||||
{
|
||||
source.AppendLine($"{indent}Timer.DelayCall({method.Name});");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableEntityGeneration.Property.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SerializableEntityGeneration
|
||||
{
|
||||
public static void GenerateSerializableProperty(
|
||||
this StringBuilder source,
|
||||
Compilation compilation,
|
||||
string indent,
|
||||
IFieldSymbol fieldSymbol,
|
||||
Accessibility getter,
|
||||
Accessibility? setter,
|
||||
bool isVirtual,
|
||||
ISymbol? parentFieldOrProperty
|
||||
)
|
||||
{
|
||||
var fieldName = fieldSymbol.Name;
|
||||
|
||||
var invalidatePropertiesAttribute = fieldSymbol
|
||||
.GetAttributes()
|
||||
.OfType<AttributeData>()
|
||||
.FirstOrDefault(
|
||||
attr => attr.AttributeClass?.Equals(
|
||||
compilation.GetTypeByMetadataName(SymbolMetadata.INVALIDATEPROPERTIES_ATTRIBUTE),
|
||||
SymbolEqualityComparer.Default
|
||||
) ?? false
|
||||
);
|
||||
|
||||
var propertyIndent = $"{indent} ";
|
||||
var innerIndent = $"{propertyIndent} ";
|
||||
|
||||
var propertyAccessor = setter > getter ? setter : getter;
|
||||
var getterAccessor = getter == propertyAccessor ? Accessibility.NotApplicable : getter;
|
||||
|
||||
source.GeneratePropertyStart(indent, propertyAccessor.Value, isVirtual, fieldSymbol);
|
||||
|
||||
// Getter
|
||||
source.GeneratePropertyGetterReturnsField(propertyIndent, fieldSymbol, getterAccessor);
|
||||
|
||||
if (setter != null && setter != Accessibility.NotApplicable)
|
||||
{
|
||||
var setterAccessor = setter == propertyAccessor ? Accessibility.NotApplicable : setter;
|
||||
|
||||
var parentSymbol = parentFieldOrProperty?.Name ?? "this";
|
||||
|
||||
// Setter
|
||||
source.GeneratePropertySetterStart(propertyIndent, false, setterAccessor.Value);
|
||||
source.AppendLine($"{innerIndent}if (value != {fieldName})");
|
||||
source.AppendLine($"{innerIndent}{{");
|
||||
source.AppendLine($"{innerIndent} {fieldName} = value;");
|
||||
source.AppendLine($"{innerIndent} {parentSymbol}.MarkDirty();");
|
||||
|
||||
if (invalidatePropertiesAttribute != null)
|
||||
{
|
||||
source.AppendLine($"{innerIndent} InvalidateProperties();");
|
||||
}
|
||||
source.AppendLine($"{innerIndent}}}");
|
||||
source.GeneratePropertyGetSetEnd(propertyIndent, false);
|
||||
}
|
||||
|
||||
source.GeneratePropertyEnd(indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableEntityGeneration.SerialCtor.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SerializableEntityGeneration
|
||||
{
|
||||
private static readonly ImmutableArray<string> _baseParameters = new[] { "serial" }.ToImmutableArray();
|
||||
public static void GenerateSerialCtor(
|
||||
this StringBuilder source,
|
||||
Compilation compilation,
|
||||
string className,
|
||||
string indent,
|
||||
bool isOverride
|
||||
)
|
||||
{
|
||||
var serialType = (ITypeSymbol)compilation.GetTypeByMetadataName("Server.Serial");
|
||||
|
||||
source.GenerateConstructorStart(
|
||||
indent,
|
||||
className,
|
||||
Accessibility.Public,
|
||||
new []{ (serialType, "serial") }.ToImmutableArray(),
|
||||
isOverride ? _baseParameters : ImmutableArray<string>.Empty
|
||||
);
|
||||
|
||||
if (!isOverride)
|
||||
{
|
||||
source.AppendLine($"{indent} Serial = serial;");
|
||||
source.AppendLine($"{indent} SetTypeRef(typeof({className}));");
|
||||
}
|
||||
|
||||
source.GenerateMethodEnd(indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableEntityGeneration.SerializeMethod.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializableMigration;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SerializableEntityGeneration
|
||||
{
|
||||
public static void GenerateSerializeMethod(
|
||||
this StringBuilder source,
|
||||
Compilation compilation,
|
||||
string indent,
|
||||
bool isOverride,
|
||||
bool encodedVersion,
|
||||
ImmutableArray<SerializableProperty> fields,
|
||||
ImmutableArray<SerializableProperty> properties,
|
||||
SortedDictionary<int, SerializableFieldSaveFlagMethods> serializableFieldSaveFlagMethodsDictionary
|
||||
)
|
||||
{
|
||||
var genericWriterInterface = compilation.GetTypeByMetadataName(SymbolMetadata.GENERIC_WRITER_INTERFACE);
|
||||
|
||||
source.GenerateMethodStart(
|
||||
indent,
|
||||
"Serialize",
|
||||
Accessibility.Public,
|
||||
isOverride,
|
||||
"void",
|
||||
ImmutableArray.Create<(ITypeSymbol, string)>((genericWriterInterface, "writer"))
|
||||
);
|
||||
|
||||
var bodyIndent = $"{indent} ";
|
||||
var innerIndent = $"{bodyIndent} ";
|
||||
|
||||
if (isOverride)
|
||||
{
|
||||
source.AppendLine($"{bodyIndent}base.Serialize(writer);");
|
||||
source.AppendLine();
|
||||
}
|
||||
|
||||
// Version
|
||||
source.AppendLine($"{bodyIndent}writer.{(encodedVersion ? "WriteEncodedInt" : "Write")}(_version);");
|
||||
|
||||
// Let's collect the flags
|
||||
if (serializableFieldSaveFlagMethodsDictionary.Count > 0)
|
||||
{
|
||||
source.AppendLine($"\n{bodyIndent}var saveFlags = SaveFlag.None;");
|
||||
|
||||
foreach (var (order, saveFlagMethods) in serializableFieldSaveFlagMethodsDictionary)
|
||||
{
|
||||
source.AppendLine($"{bodyIndent}if ({saveFlagMethods.DetermineFieldShouldSerialize!.Name}())\n{bodyIndent}{{");
|
||||
|
||||
var propertyName = properties[order].Name;
|
||||
source.AppendLine($"{innerIndent}saveFlags |= SaveFlag.{propertyName};");
|
||||
|
||||
source.AppendLine($"{bodyIndent}}}");
|
||||
}
|
||||
|
||||
source.AppendLine($"{bodyIndent}writer.WriteEnum(saveFlags);");
|
||||
}
|
||||
|
||||
for (var i = 0; i < properties.Length; i++)
|
||||
{
|
||||
var field = fields[i];
|
||||
var property = properties[i];
|
||||
if (serializableFieldSaveFlagMethodsDictionary.ContainsKey(property.Order))
|
||||
{
|
||||
// Special case
|
||||
if (property.Type != "bool")
|
||||
{
|
||||
source.AppendLine($"\n{bodyIndent}if ((saveFlags & SaveFlag.{property.Name}) != 0)\n{bodyIndent}{{");
|
||||
SerializableMigrationRulesEngine.Rules[property.Rule]
|
||||
.GenerateSerializationMethod(
|
||||
source,
|
||||
innerIndent,
|
||||
field
|
||||
);
|
||||
source.AppendLine($"{bodyIndent}}}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
source.AppendLine();
|
||||
SerializableMigrationRulesEngine.Rules[property.Rule]
|
||||
.GenerateSerializationMethod(
|
||||
source,
|
||||
bodyIndent,
|
||||
field
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
source.GenerateMethodEnd(indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public record SerializableFieldSaveFlagMethods
|
||||
{
|
||||
public IMethodSymbol? DetermineFieldShouldSerialize { get; init; }
|
||||
|
||||
public IMethodSymbol? GetFieldDefaultValue { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializationEntityGeneration.ContentStruct.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializableMigration;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SerializableEntityGeneration
|
||||
{
|
||||
public static void GenerateMigrationContentStruct(
|
||||
this StringBuilder source,
|
||||
Compilation compilation,
|
||||
string indent,
|
||||
SerializableMetadata migration,
|
||||
INamedTypeSymbol classSymbol
|
||||
)
|
||||
{
|
||||
source.AppendLine($"{indent}ref struct V{migration.Version}Content");
|
||||
source.AppendLine($"{indent}{{");
|
||||
var properties = migration.Properties ?? ImmutableArray<SerializableProperty>.Empty;
|
||||
|
||||
foreach (var serializableProperty in properties)
|
||||
{
|
||||
SerializableMigrationRulesEngine.Rules[serializableProperty.Rule].GenerateMigrationProperty(
|
||||
source, compilation, $"{indent} ", serializableProperty
|
||||
);
|
||||
}
|
||||
|
||||
var innerIndent = $"{indent} ";
|
||||
|
||||
var usesSaveFlags = properties.Any(p => p.UsesSaveFlag == true);
|
||||
|
||||
if (usesSaveFlags)
|
||||
{
|
||||
source.AppendLine();
|
||||
source.GenerateEnumStart(
|
||||
$"V{migration.Version}SaveFlag",
|
||||
$"{indent} ",
|
||||
true,
|
||||
Accessibility.Private
|
||||
);
|
||||
|
||||
source.GenerateEnumValue(innerIndent, true, "None", -1);
|
||||
int index = 0;
|
||||
foreach (var property in properties)
|
||||
{
|
||||
if (property.UsesSaveFlag == true)
|
||||
{
|
||||
source.GenerateEnumValue(innerIndent, true, property.Name, index++);
|
||||
}
|
||||
}
|
||||
|
||||
source.GenerateEnumEnd($"{indent} ");
|
||||
}
|
||||
|
||||
source.AppendLine($"{indent} internal V{migration.Version}Content(IGenericReader reader, {classSymbol.ToDisplayString()} entity)");
|
||||
source.AppendLine($"{indent} {{");
|
||||
|
||||
if (usesSaveFlags)
|
||||
{
|
||||
source.AppendLine($"{innerIndent}var saveFlags = reader.ReadEnum<V{migration.Version}SaveFlag>();");
|
||||
}
|
||||
|
||||
if (properties.Length > 0)
|
||||
{
|
||||
foreach (var property in properties)
|
||||
{
|
||||
if (property.UsesSaveFlag == true)
|
||||
{
|
||||
source.AppendLine();
|
||||
// Special case
|
||||
if (property.Type == "bool")
|
||||
{
|
||||
source.AppendLine($"{innerIndent}{property.Name} = (saveFlags & V{migration.Version}SaveFlag.{property.Name}) != 0;");
|
||||
}
|
||||
else
|
||||
{
|
||||
source.AppendLine($"{innerIndent}if ((saveFlags & V{migration.Version}SaveFlag.{property.Name}) != 0)\n{innerIndent}{{");
|
||||
|
||||
SerializableMigrationRulesEngine.Rules[property.Rule].GenerateDeserializationMethod(
|
||||
source,
|
||||
$"{innerIndent} ",
|
||||
property,
|
||||
"entity",
|
||||
true
|
||||
);
|
||||
|
||||
source.AppendLine($"{innerIndent}}}\n{innerIndent}else\n{innerIndent}{{");
|
||||
source.AppendLine($"{innerIndent} {property.Name} = default;");
|
||||
source.AppendLine($"{innerIndent}}}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SerializableMigrationRulesEngine.Rules[property.Rule].GenerateDeserializationMethod(
|
||||
source,
|
||||
innerIndent,
|
||||
property,
|
||||
"entity",
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source.AppendLine($"{indent} }}");
|
||||
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: IPostDeserializeMethod.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializableMigration
|
||||
{
|
||||
public interface IPostDeserializeMethod
|
||||
{
|
||||
public void PostDeserializeMethod(
|
||||
StringBuilder source,
|
||||
string indent,
|
||||
SerializableProperty property,
|
||||
Compilation compilation,
|
||||
INamedTypeSymbol classSymbol
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializableMigration
|
||||
{
|
||||
public interface ISerializableMigrationRule
|
||||
{
|
||||
string RuleName { get; }
|
||||
|
||||
void GenerateMigrationProperty(
|
||||
StringBuilder source,
|
||||
Compilation compilation,
|
||||
string indent,
|
||||
SerializableProperty serializableProperty
|
||||
);
|
||||
|
||||
bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
);
|
||||
|
||||
void GenerateDeserializationMethod(
|
||||
StringBuilder source,
|
||||
string indent,
|
||||
SerializableProperty property,
|
||||
string? parentReference,
|
||||
bool isMigration = false
|
||||
);
|
||||
|
||||
void GenerateSerializationMethod(
|
||||
StringBuilder source,
|
||||
string indent,
|
||||
SerializableProperty property
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: ArrayMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class ArrayMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(ArrayMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol is not IArrayTypeSymbol arrayTypeSymbol)
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var serializableArrayType = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
"ArrayEntry",
|
||||
arrayTypeSymbol.ElementType,
|
||||
0,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
parentSymbol,
|
||||
null
|
||||
);
|
||||
|
||||
var length = serializableArrayType.RuleArguments?.Length?? 0;
|
||||
ruleArguments = new string[length + 2];
|
||||
ruleArguments[0] = arrayTypeSymbol.ElementType.ToDisplayString();
|
||||
ruleArguments[1] = serializableArrayType.Rule;
|
||||
if (length > 0)
|
||||
{
|
||||
Array.Copy(serializableArrayType.RuleArguments!, 0, ruleArguments, 2, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]];
|
||||
var arrayElementRuleArguments = new string[ruleArguments.Length - 2];
|
||||
Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2);
|
||||
|
||||
var propertyIndex = $"{property.Name}Index";
|
||||
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}{{");
|
||||
|
||||
var serializableArrayElement = new SerializableProperty
|
||||
{
|
||||
Name = $"{property.Name}[{propertyIndex}]",
|
||||
Type = ruleArguments[0],
|
||||
Rule = arrayElementRule.RuleName,
|
||||
RuleArguments = arrayElementRuleArguments
|
||||
};
|
||||
|
||||
arrayElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableArrayElement, parentReference);
|
||||
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]];
|
||||
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";
|
||||
var propertyLength = $"{propertyVarPrefix}Length";
|
||||
source.AppendLine($"{indent}var {propertyLength} = {property.Name}?.Length ?? 0;");
|
||||
source.AppendLine($"{indent}writer.WriteEncodedInt({propertyLength});");
|
||||
source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyLength}; {propertyIndex}++)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
|
||||
var serializableArrayElement = new SerializableProperty
|
||||
{
|
||||
Name = $"{property.Name}![{propertyIndex}]",
|
||||
Type = ruleArguments[0],
|
||||
Rule = arrayElementRule.RuleName,
|
||||
RuleArguments = arrayElementRuleArguments
|
||||
};
|
||||
|
||||
arrayElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableArrayElement);
|
||||
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: DictionaryMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class DictionaryMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(DictionaryMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsDictionary(compilation))
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var keySymbolType = namedTypeSymbol.TypeArguments[0];
|
||||
|
||||
var serializableKeyProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
"KeyEntry",
|
||||
keySymbolType,
|
||||
0,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
parentSymbol,
|
||||
null
|
||||
);
|
||||
|
||||
var valueSymbolType = namedTypeSymbol.TypeArguments[1];
|
||||
|
||||
var serializableValueProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
"ValueEntry",
|
||||
valueSymbolType,
|
||||
0,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
parentSymbol,
|
||||
null
|
||||
);
|
||||
|
||||
var extraOptions = "";
|
||||
if (attributes.Any(a => a.IsTidy(compilation)))
|
||||
{
|
||||
extraOptions += "@Tidy";
|
||||
}
|
||||
|
||||
var keyArgumentsLength = serializableKeyProperty.RuleArguments?.Length ?? 0;
|
||||
var valueArgumentsLength = serializableValueProperty.RuleArguments?.Length ?? 0;
|
||||
var index = 0;
|
||||
|
||||
ruleArguments = new string[7 + keyArgumentsLength + valueArgumentsLength];
|
||||
ruleArguments[index++] = extraOptions;
|
||||
ruleArguments[index++] = keySymbolType.ToDisplayString();
|
||||
ruleArguments[index++] = serializableKeyProperty.Rule;
|
||||
ruleArguments[index++] = keyArgumentsLength.ToString();
|
||||
|
||||
if (keyArgumentsLength > 0)
|
||||
{
|
||||
Array.Copy(serializableKeyProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength);
|
||||
index += keyArgumentsLength;
|
||||
}
|
||||
|
||||
ruleArguments[index++] = valueSymbolType.ToDisplayString();
|
||||
ruleArguments[index++] = serializableValueProperty.Rule;
|
||||
ruleArguments[index++] = valueArgumentsLength.ToString();
|
||||
|
||||
if (valueArgumentsLength > 0)
|
||||
{
|
||||
Array.Copy(serializableValueProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var index = 1;
|
||||
var keyType = ruleArguments![index++];
|
||||
|
||||
var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (keyRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
index += keyRuleArguments.Length;
|
||||
}
|
||||
|
||||
var valueType = ruleArguments[index++];
|
||||
var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var valueRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (valueRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
var propertyIndex = $"{propertyVarPrefix}Index";
|
||||
var propertyKeyEntry = $"{propertyVarPrefix}Key";
|
||||
var propertyValueEntry = $"{propertyVarPrefix}Value";
|
||||
var propertyCount = $"{propertyVarPrefix}Count";
|
||||
|
||||
source.AppendLine($"{indent}{ruleArguments[1]} {propertyKeyEntry};");
|
||||
source.AppendLine($"{indent}{valueType} {propertyValueEntry};");
|
||||
source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();");
|
||||
source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.Dictionary<{keyType}, {valueType}>({propertyCount});");
|
||||
source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
|
||||
var serializableKeyElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyKeyEntry,
|
||||
Type = keyType,
|
||||
Rule = keyElementRule.RuleName,
|
||||
RuleArguments = keyRuleArguments
|
||||
};
|
||||
|
||||
keyElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableKeyElement, parentReference);
|
||||
|
||||
var serializableValueElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyValueEntry,
|
||||
Type = valueType,
|
||||
Rule = valueElementRule.RuleName,
|
||||
RuleArguments = valueRuleArguments
|
||||
};
|
||||
|
||||
valueElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableValueElement, parentReference);
|
||||
source.AppendLine($"{indent} {propertyName}.Add({propertyKeyEntry}, {propertyValueEntry});");
|
||||
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var index = 0;
|
||||
var shouldTidy = ruleArguments![index++].Contains("@Tidy");
|
||||
var keyType = ruleArguments![index++];
|
||||
|
||||
var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![index++]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (keyRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
index += keyRuleArguments.Length;
|
||||
}
|
||||
|
||||
var valueType = ruleArguments[index++];
|
||||
var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var valueRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (valueRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
var propertyKeyEntry = $"{propertyVarPrefix}Key";
|
||||
var propertyValueEntry = $"{propertyVarPrefix}Value";
|
||||
var propertyCount = $"{propertyVarPrefix}Count";
|
||||
|
||||
if (shouldTidy)
|
||||
{
|
||||
source.AppendLine($"{indent}{property.Name}?.Tidy();");
|
||||
}
|
||||
source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;");
|
||||
source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});");
|
||||
source.AppendLine($"{indent}if ({propertyCount} > 0)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
source.AppendLine($"{indent} foreach (var ({propertyKeyEntry}, {propertyValueEntry}) in {property.Name}!)");
|
||||
source.AppendLine($"{indent} {{");
|
||||
|
||||
var serializableKeyElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyKeyEntry,
|
||||
Type = keyType,
|
||||
Rule = keyElementRule.RuleName,
|
||||
RuleArguments = keyRuleArguments
|
||||
};
|
||||
|
||||
keyElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableKeyElement);
|
||||
|
||||
var serializableValueElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyValueEntry,
|
||||
Type = valueType,
|
||||
Rule = valueElementRule.RuleName,
|
||||
RuleArguments = valueRuleArguments
|
||||
};
|
||||
|
||||
valueElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableValueElement);
|
||||
|
||||
source.AppendLine($"{indent} }}");
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: EnumMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class EnumMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(EnumMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol is not ITypeSymbol typeSymbol || !typeSymbol.IsEnum())
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
ruleArguments = Array.Empty<string>();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
source.AppendLine($"{indent}{property.Name} = reader.ReadEnum<{property.Type}>();");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
source.AppendLine($"{indent}writer.WriteEnum<{property.Type}>({property.Name});");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: HashSetMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class HashSetMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(HashSetMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsHashSet(compilation))
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var setTypeSymbol = namedTypeSymbol.TypeArguments[0];
|
||||
|
||||
var serializableSetType = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
"SetEntry",
|
||||
setTypeSymbol,
|
||||
0,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
parentSymbol,
|
||||
null
|
||||
);
|
||||
|
||||
var extraOptions = "";
|
||||
if (attributes.Any(a => a.IsTidy(compilation)))
|
||||
{
|
||||
extraOptions += "@Tidy";
|
||||
}
|
||||
|
||||
var length = serializableSetType.RuleArguments?.Length ?? 0;
|
||||
ruleArguments = new string[length + 3];
|
||||
ruleArguments[0] = extraOptions;
|
||||
ruleArguments[1] = setTypeSymbol.ToDisplayString();
|
||||
ruleArguments[2] = serializableSetType.Rule;
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
Array.Copy(serializableSetType.RuleArguments, 0, ruleArguments, 3, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal);
|
||||
var argumentsOffset = hasExtraOptions ? 1 : 0;
|
||||
|
||||
var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]];
|
||||
var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset];
|
||||
Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset);
|
||||
|
||||
var propertyName = property.Name;
|
||||
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[argumentsOffset]} {propertyEntry};");
|
||||
source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();");
|
||||
source.AppendLine($"{indent}{property.Name} = new System.Collections.Generic.HashSet<{ruleArguments[argumentsOffset]}>({propertyCount});");
|
||||
source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
|
||||
var serializableSetElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyEntry,
|
||||
Type = ruleArguments[argumentsOffset],
|
||||
Rule = setElementRule.RuleName,
|
||||
RuleArguments = setElementRuleArguments
|
||||
};
|
||||
|
||||
setElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableSetElement, parentReference);
|
||||
source.AppendLine($"{indent} {property.Name}.Add({propertyEntry});");
|
||||
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal);
|
||||
var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy");
|
||||
var argumentsOffset = hasExtraOptions ? 1 : 0;
|
||||
|
||||
var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]];
|
||||
var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset];
|
||||
Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset);
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
var propertyEntry = $"{propertyVarPrefix}Entry";
|
||||
var propertyCount = $"{propertyVarPrefix}Count";
|
||||
|
||||
if (shouldTidy)
|
||||
{
|
||||
source.AppendLine($"{indent}{property.Name}?.Tidy();");
|
||||
}
|
||||
source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;");
|
||||
source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});");
|
||||
source.AppendLine($"{indent}if ({propertyCount} > 0)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)");
|
||||
source.AppendLine($"{indent} {{");
|
||||
|
||||
var serializableSetElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyEntry,
|
||||
Type = ruleArguments[argumentsOffset],
|
||||
Rule = setElementRule.RuleName,
|
||||
RuleArguments = setElementRuleArguments
|
||||
};
|
||||
|
||||
setElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableSetElement);
|
||||
|
||||
source.AppendLine($"{indent} }}");
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: KeyValuePairMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class KeyValuePairMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(KeyValuePairMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsKeyValuePair(compilation))
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var keySymbolType = namedTypeSymbol.TypeArguments[0];
|
||||
|
||||
var keySerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
"key",
|
||||
keySymbolType,
|
||||
0,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
parentSymbol,
|
||||
null
|
||||
);
|
||||
|
||||
var valueSymbolType = namedTypeSymbol.TypeArguments[1];
|
||||
|
||||
var valueSerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
"value",
|
||||
valueSymbolType,
|
||||
1,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
parentSymbol,
|
||||
null
|
||||
);
|
||||
|
||||
var keyArgumentsLength = keySerializedProperty.RuleArguments?.Length ?? 0;
|
||||
var valueArgumentsLength = valueSerializedProperty.RuleArguments?.Length ?? 0;
|
||||
var index = 0;
|
||||
|
||||
// Key
|
||||
ruleArguments = new string[6 + keyArgumentsLength + valueArgumentsLength];
|
||||
ruleArguments[index++] = ""; // Extra options
|
||||
ruleArguments[index++] = keySymbolType.ToDisplayString();
|
||||
ruleArguments[index++] = keySerializedProperty.Rule;
|
||||
ruleArguments[index++] = keyArgumentsLength.ToString();
|
||||
if (keyArgumentsLength > 0)
|
||||
{
|
||||
Array.Copy(keySerializedProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength);
|
||||
index += keyArgumentsLength;
|
||||
}
|
||||
|
||||
// Value
|
||||
ruleArguments[index++] = valueSymbolType.ToDisplayString();
|
||||
ruleArguments[index++] = valueSerializedProperty.Rule;
|
||||
|
||||
if (valueArgumentsLength > 0)
|
||||
{
|
||||
Array.Copy(valueSerializedProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var index = 1; // skip extra options
|
||||
var keyType = ruleArguments![index++];
|
||||
var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (keyRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
index += keyRuleArguments.Length;
|
||||
}
|
||||
|
||||
var serializableKeyProperty = new SerializableProperty
|
||||
{
|
||||
Name = "key",
|
||||
Type = keyType,
|
||||
Rule = keyRule.RuleName,
|
||||
RuleArguments = keyRuleArguments
|
||||
};
|
||||
|
||||
keyRule.GenerateDeserializationMethod(
|
||||
source,
|
||||
indent,
|
||||
serializableKeyProperty,
|
||||
parentReference
|
||||
);
|
||||
|
||||
var valueType = ruleArguments[index++];
|
||||
var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var valueRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (valueRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
}
|
||||
|
||||
var serializableValueProperty = new SerializableProperty
|
||||
{
|
||||
Name = "value",
|
||||
Type = valueType,
|
||||
Rule = valueRule.RuleName,
|
||||
RuleArguments = valueRuleArguments
|
||||
};
|
||||
|
||||
valueRule.GenerateDeserializationMethod(
|
||||
source,
|
||||
indent,
|
||||
serializableValueProperty,
|
||||
parentReference
|
||||
);
|
||||
|
||||
source.AppendLine(
|
||||
$"{indent}{property.Name} = new {SymbolMetadata.KEYVALUEPAIR_STRUCT}<{keyType}, {valueType}>(key, value);"
|
||||
);
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var index = 1; // skip extra options
|
||||
var keyType = ruleArguments![index++];
|
||||
var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var keyRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (keyRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length);
|
||||
index += keyRuleArguments.Length;
|
||||
}
|
||||
|
||||
var serializableKeyProperty = new SerializableProperty
|
||||
{
|
||||
Name = $"{property.Name}.Key",
|
||||
Type = keyType,
|
||||
Rule = keyRule.RuleName,
|
||||
RuleArguments = keyRuleArguments
|
||||
};
|
||||
|
||||
keyRule.GenerateSerializationMethod(
|
||||
source,
|
||||
indent,
|
||||
serializableKeyProperty
|
||||
);
|
||||
|
||||
var valueType = ruleArguments[index++];
|
||||
var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]];
|
||||
var valueRuleArguments = new string[int.Parse(ruleArguments[index++])];
|
||||
|
||||
if (valueRuleArguments.Length > 0)
|
||||
{
|
||||
Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length);
|
||||
}
|
||||
|
||||
var serializableValueProperty = new SerializableProperty
|
||||
{
|
||||
Name = $"{property.Name}.Value",
|
||||
Type = valueType,
|
||||
Rule = valueRule.RuleName,
|
||||
RuleArguments = valueRuleArguments
|
||||
};
|
||||
|
||||
valueRule.GenerateSerializationMethod(
|
||||
source,
|
||||
indent,
|
||||
serializableValueProperty
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: ListMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class ListMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(ListMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsList(compilation))
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var listTypeSymbol = namedTypeSymbol.TypeArguments[0];
|
||||
|
||||
var serializableListType = SerializableMigrationRulesEngine.GenerateSerializableProperty(
|
||||
compilation,
|
||||
"ListEntry",
|
||||
listTypeSymbol,
|
||||
0,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
parentSymbol,
|
||||
null
|
||||
);
|
||||
|
||||
var extraOptions = "";
|
||||
if (attributes.Any(a => a.IsTidy(compilation)))
|
||||
{
|
||||
extraOptions += "@Tidy";
|
||||
}
|
||||
|
||||
var length = serializableListType.RuleArguments?.Length ?? 0;
|
||||
ruleArguments = new string[length + 3];
|
||||
ruleArguments[0] = extraOptions;
|
||||
ruleArguments[1] = listTypeSymbol.ToDisplayString();
|
||||
ruleArguments[2] = serializableListType.Rule;
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
Array.Copy(serializableListType.RuleArguments!, 0, ruleArguments, 3, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal);
|
||||
var argumentsOffset = hasExtraOptions ? 1 : 0;
|
||||
|
||||
var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[argumentsOffset + 1]];
|
||||
|
||||
var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset];
|
||||
Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset);
|
||||
|
||||
var propertyName = property.Name;
|
||||
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[argumentsOffset]} {propertyEntry};");
|
||||
source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();");
|
||||
source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.List<{ruleArguments[argumentsOffset]}>({propertyCount});");
|
||||
source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
|
||||
var serializableListElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyEntry,
|
||||
Type = ruleArguments[argumentsOffset],
|
||||
Rule = listElementRule.RuleName,
|
||||
RuleArguments = listElementRuleArguments
|
||||
};
|
||||
|
||||
listElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableListElement, parentReference);
|
||||
source.AppendLine($"{indent} {propertyName}.Add({propertyEntry});");
|
||||
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal);
|
||||
var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy");
|
||||
var argumentsOffset = hasExtraOptions ? 1 : 0;
|
||||
|
||||
var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]];
|
||||
var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset];
|
||||
Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset);
|
||||
|
||||
var propertyName = property.Name;
|
||||
var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}";
|
||||
var propertyEntry = $"{propertyVarPrefix}Entry";
|
||||
var propertyCount = $"{propertyVarPrefix}Count";
|
||||
|
||||
if (shouldTidy)
|
||||
{
|
||||
source.AppendLine($"{indent}{property.Name}?.Tidy();");
|
||||
}
|
||||
source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;");
|
||||
source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});");
|
||||
source.AppendLine($"{indent}if ({propertyCount} > 0)");
|
||||
source.AppendLine($"{indent}{{");
|
||||
source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)");
|
||||
source.AppendLine($"{indent} {{");
|
||||
|
||||
var serializableListElement = new SerializableProperty
|
||||
{
|
||||
Name = propertyEntry,
|
||||
Type = ruleArguments[argumentsOffset],
|
||||
Rule = listElementRule.RuleName,
|
||||
RuleArguments = listElementRuleArguments
|
||||
};
|
||||
|
||||
listElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableListElement);
|
||||
|
||||
source.AppendLine($"{indent} }}");
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public abstract class MigrationRule : ISerializableMigrationRule
|
||||
{
|
||||
public abstract string RuleName { get; }
|
||||
|
||||
public virtual void GenerateMigrationProperty(
|
||||
StringBuilder source, Compilation compilation, string indent, SerializableProperty serializableProperty
|
||||
)
|
||||
{
|
||||
var propertyType = serializableProperty.Type;
|
||||
var type = compilation.GetTypeByMetadataName(propertyType)?.IsValueType == true
|
||||
|| SymbolMetadata.IsPrimitiveFromTypeDisplayString(propertyType) && propertyType != "bool"
|
||||
? $"{propertyType}{(serializableProperty.UsesSaveFlag == true ? "?" : "")}" : propertyType;
|
||||
|
||||
source.AppendLine($"{indent}internal readonly {type} {serializableProperty.Name};");
|
||||
}
|
||||
|
||||
public abstract bool GenerateRuleState(
|
||||
Compilation compilation, ISymbol symbol, ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes, ISymbol? parentSymbol, out string[] ruleArguments
|
||||
);
|
||||
|
||||
public abstract void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
);
|
||||
|
||||
public abstract void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property);
|
||||
}
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: PrimitiveTypeMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class PrimitiveTypeMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(PrimitiveTypeMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol.IsIpAddress(compilation) || symbol.IsTimeSpan(compilation))
|
||||
{
|
||||
ruleArguments = Array.Empty<string>();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
symbol is not ITypeSymbol {
|
||||
SpecialType: not (not
|
||||
SpecialType.System_Boolean and not
|
||||
SpecialType.System_SByte and not
|
||||
SpecialType.System_Int16 and not
|
||||
SpecialType.System_Int32 and not
|
||||
SpecialType.System_Int64 and not
|
||||
SpecialType.System_Byte and not
|
||||
SpecialType.System_UInt16 and not
|
||||
SpecialType.System_UInt32 and not
|
||||
SpecialType.System_UInt64 and not
|
||||
SpecialType.System_Single and not
|
||||
SpecialType.System_Double and not
|
||||
SpecialType.System_String and not
|
||||
SpecialType.System_Decimal and not
|
||||
SpecialType.System_DateTime)
|
||||
} typeSymbol
|
||||
)
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
ruleArguments = typeSymbol.SpecialType switch
|
||||
{
|
||||
SpecialType.System_Int32 when attributes.Any(a => a.IsEncodedInt(compilation)) =>
|
||||
new[] { "EncodedInt" },
|
||||
SpecialType.System_DateTime when attributes.Any(a => a.IsDeltaDateTime(compilation)) =>
|
||||
new[] { "DeltaTime" },
|
||||
SpecialType.System_String when attributes.Any(a => a.IsInternString(compilation)) =>
|
||||
new[] { "InternString" },
|
||||
_ => new[] { "" }
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null;
|
||||
|
||||
const string ipAddress = SymbolMetadata.IPADDRESS_CLASS;
|
||||
const string timeSpan = SymbolMetadata.TIMESPAN_STRUCT;
|
||||
const string date = "System.DateTime";
|
||||
|
||||
var readMethod = property.Type switch
|
||||
{
|
||||
"bool" => "ReadBool",
|
||||
"sbyte" => "ReadSByte",
|
||||
"short" => "ReadShort",
|
||||
"int" when argument == "EncodedInt" => "ReadEncodedInt",
|
||||
"int" => "ReadInt",
|
||||
"long" => "ReadLong",
|
||||
"byte" => "ReadByte",
|
||||
"ushort" => "ReadUShort",
|
||||
"uint" => "ReadUInt",
|
||||
"ulong" => "ReadULong",
|
||||
"float" => "ReadFloat",
|
||||
"double" => "ReadDouble",
|
||||
"string" => "ReadString",
|
||||
"decimal" => "ReadDecimal",
|
||||
date when argument == "DeltaTime" => "ReadDeltaTime",
|
||||
date => "ReadDateTime",
|
||||
ipAddress => "ReadIPAddress",
|
||||
timeSpan => "ReadTimeSpan"
|
||||
};
|
||||
|
||||
var readArgument = readMethod == "ReadString" && argument == "InternString" ? "true" : "";
|
||||
|
||||
source.AppendLine($"{indent}{propertyName} = reader.{readMethod}({readArgument});");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null;
|
||||
|
||||
var writeMethod = property.Type switch
|
||||
{
|
||||
"System.DateTime" when argument == "DeltaTime" => "WriteDeltaTime",
|
||||
"int" when argument == "EncodedInt" => "WriteEncodedInt",
|
||||
_ => "Write"
|
||||
};
|
||||
|
||||
source.AppendLine($"{indent}writer.{writeMethod}({propertyName});");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: PrimitiveUOTypeMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class PrimitiveUOTypeMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(PrimitiveUOTypeMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
ruleArguments = symbol switch
|
||||
{
|
||||
_ when symbol.IsPoint2D(compilation) => new[] { "Point2D" },
|
||||
_ when symbol.IsPoint3D(compilation) => new[] { "Point3D" },
|
||||
_ when symbol.IsRectangle2D(compilation) => new[] { "Rect2D" },
|
||||
_ when symbol.IsRectangle3D(compilation) => new[] { "Rect3D" },
|
||||
_ when symbol.IsRace(compilation) => new[] { "Race" },
|
||||
_ when symbol.IsMap(compilation) => new[] { "Map" },
|
||||
_ when symbol.IsBitArray(compilation) => new[] { "BitArray" },
|
||||
_ => null
|
||||
};
|
||||
|
||||
return ruleArguments != null;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
source.AppendLine($"{indent}{propertyName} = reader.Read{property.RuleArguments?[0] ?? ""}();");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
source.AppendLine($"{indent}writer.Write({propertyName});");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: RawSerializableMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class RawSerializableMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(RawSerializableMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol is not ITypeSymbol typeSymbol)
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!typeSymbol.HasRawSerializableInterface(compilation, embeddedSerializableTypes))
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
ruleArguments = new[] { "" };
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
source.AppendLine($"{indent}{propertyName} = new {property.Type}({parentReference ?? "this"});");
|
||||
source.AppendLine($"{indent}{propertyName}.Deserialize(reader);");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
source.AppendLine($"{indent}{propertyName}.Serialize(writer);");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableInterfaceMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class SerializableInterfaceMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(SerializableInterfaceMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (symbol is ITypeSymbol typeSymbol && typeSymbol.HasSerializableInterface(compilation, serializableTypes))
|
||||
{
|
||||
ruleArguments = Array.Empty<string>();
|
||||
return true;
|
||||
}
|
||||
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
source.AppendLine($"{indent}{propertyName} = reader.ReadEntity<{property.Type}>();");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
source.AppendLine($"{indent}writer.Write({propertyName});");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializationMethodSignatureMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class SerializationMethodSignatureMigrationRule : MigrationRule
|
||||
{
|
||||
public override string RuleName => nameof(SerializationMethodSignatureMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if ((symbol as ITypeSymbol)?.HasPublicSerializeMethod(compilation, serializableTypes) != true)
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbol is not INamedTypeSymbol namedTypeSymbol ||
|
||||
!namedTypeSymbol.HasGenericReaderCtor(compilation, parentSymbol, out var requiresParent))
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
ruleArguments = new[] { requiresParent ? "DeserializationRequiresParent" : "" };
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
var argument = property.RuleArguments?.Length >= 1 &&
|
||||
property.RuleArguments[0] == "DeserializationRequiresParent" ? ", this" : "";
|
||||
|
||||
source.AppendLine($"{indent}{propertyName} = new {property.Type}(reader{argument});");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
source.AppendLine($"{indent}{propertyName}.Serialize(writer);");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: TimerMigrationRule.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration;
|
||||
|
||||
public class TimerMigrationRule : MigrationRule, IPostDeserializeMethod
|
||||
{
|
||||
public override string RuleName => nameof(TimerMigrationRule);
|
||||
|
||||
public override bool GenerateRuleState(
|
||||
Compilation compilation,
|
||||
ISymbol symbol,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
out string[] ruleArguments
|
||||
)
|
||||
{
|
||||
if (!(symbol is ITypeSymbol typeSymbol && typeSymbol.IsTimer(compilation)))
|
||||
{
|
||||
ruleArguments = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
ruleArguments = attributes.Any(a => a.IsTimerDrift(compilation))
|
||||
? new[] { "@TimerDrift" }
|
||||
: new[] { "" };
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GenerateMigrationProperty(
|
||||
StringBuilder source, Compilation compilation, string indent, SerializableProperty serializableProperty
|
||||
)
|
||||
{
|
||||
source.AppendLine($"{indent}internal readonly System.DateTime {serializableProperty.Name}Next;");
|
||||
source.AppendLine($"{indent}internal readonly System.TimeSpan {serializableProperty.Name}Delay;");
|
||||
}
|
||||
|
||||
public override void GenerateDeserializationMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false
|
||||
)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var driftTimer = ruleArguments![0].Contains("@TimerDrift");
|
||||
|
||||
var readTimer = driftTimer ? "reader.ReadDeltaTime()" : "reader.ReadDateTime()";
|
||||
var useVar = isMigration ? "" : "var ";
|
||||
source.AppendLine($"{indent}{useVar}{propertyName}Next = {readTimer};");
|
||||
source.AppendLine($"{indent}{useVar}{propertyName}Delay = {propertyName}Next == System.DateTime.MinValue ? System.TimeSpan.MinValue : {propertyName}Next - Core.Now;");
|
||||
}
|
||||
|
||||
public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property)
|
||||
{
|
||||
var expectedRule = RuleName;
|
||||
var ruleName = property.Rule;
|
||||
if (expectedRule != ruleName)
|
||||
{
|
||||
throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}.");
|
||||
}
|
||||
|
||||
var propertyName = property.Name;
|
||||
var ruleArguments = property.RuleArguments;
|
||||
var driftTimer = ruleArguments![0].Contains("@TimerDrift");
|
||||
|
||||
var writerMethod = driftTimer ? "WriteDeltaTime" : "Write";
|
||||
source.AppendLine($"{indent}writer.{writerMethod}({propertyName}?.Next ?? System.DateTime.MinValue);");
|
||||
}
|
||||
|
||||
public void PostDeserializeMethod(
|
||||
StringBuilder source, string indent, SerializableProperty property, Compilation compilation, INamedTypeSymbol classSymbol
|
||||
)
|
||||
{
|
||||
var deserializeTimerMethod = classSymbol
|
||||
.GetMembers()
|
||||
.OfType<IMethodSymbol>()
|
||||
.FirstOrDefault(
|
||||
m =>
|
||||
{
|
||||
if (!m.ReturnsVoid || m.Parameters.Length != 1 || !m.Parameters[0].Type.IsTimeSpan(compilation))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m.GetAttributes()
|
||||
.FirstOrDefault(
|
||||
attr =>
|
||||
{
|
||||
if (!SymbolEqualityComparer.Default.Equals(
|
||||
attr.AttributeClass,
|
||||
compilation.GetTypeByMetadataName(
|
||||
SymbolMetadata.DESERIALIZE_TIMER_FIELD_ATTRIBUTE
|
||||
)
|
||||
))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var order = (int)attr.ConstructorArguments[0].Value!;
|
||||
return order == property.Order;
|
||||
}
|
||||
) != null;
|
||||
}
|
||||
) ?? throw new Exception("Serializing a timer requires a method with the DeserializeTimerField attribute to handle creating the timer itself.");
|
||||
|
||||
source.AppendLine($"{indent}{deserializeTimerMethod.Name}({property.Name}Delay);");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableMigration.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SerializableMigration
|
||||
{
|
||||
public record SerializableMetadata
|
||||
{
|
||||
[JsonPropertyName("version")]
|
||||
public int Version { get; init; }
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; init; }
|
||||
|
||||
[JsonPropertyName("properties")]
|
||||
public ImmutableArray<SerializableProperty>? Properties { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SerializableMigration
|
||||
{
|
||||
public class SerializableMetadataComparer : IComparer<SerializableMetadata>
|
||||
{
|
||||
public int Compare(SerializableMetadata x, SerializableMetadata y)
|
||||
{
|
||||
if (ReferenceEquals(x, y))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(null, y))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(null, x))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return x.Version.CompareTo(y.Version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableMigrationRulesEngine.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializableMigration
|
||||
{
|
||||
public static class SerializableMigrationRulesEngine
|
||||
{
|
||||
public static readonly Dictionary<string, ISerializableMigrationRule> Rules = new();
|
||||
|
||||
static SerializableMigrationRulesEngine()
|
||||
{
|
||||
var rules = new ISerializableMigrationRule[]
|
||||
{
|
||||
new EnumMigrationRule(),
|
||||
new ListMigrationRule(),
|
||||
new ArrayMigrationRule(),
|
||||
new HashSetMigrationRule(),
|
||||
new DictionaryMigrationRule(),
|
||||
new KeyValuePairMigrationRule(),
|
||||
new PrimitiveTypeMigrationRule(),
|
||||
new PrimitiveUOTypeMigrationRule(),
|
||||
new SerializableInterfaceMigrationRule(),
|
||||
new SerializationMethodSignatureMigrationRule(),
|
||||
new RawSerializableMigrationRule(),
|
||||
new TimerMigrationRule()
|
||||
};
|
||||
|
||||
foreach (var rule in rules)
|
||||
{
|
||||
Rules.Add(rule.RuleName, rule);
|
||||
}
|
||||
}
|
||||
|
||||
public static SerializableProperty? GenerateSerializableProperty(
|
||||
Compilation compilation,
|
||||
ISymbol fieldOrPropertySymbol,
|
||||
int order,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
SerializableFieldSaveFlagMethods? serializableFieldSaveFlagMethods
|
||||
)
|
||||
{
|
||||
string propertyName;
|
||||
ITypeSymbol propertyType;
|
||||
|
||||
if (fieldOrPropertySymbol is IFieldSymbol fieldSymbol)
|
||||
{
|
||||
propertyName = fieldSymbol.Name;
|
||||
propertyType = fieldSymbol.Type;
|
||||
}
|
||||
else if (fieldOrPropertySymbol is IPropertySymbol propertySymbol)
|
||||
{
|
||||
propertyName = fieldOrPropertySymbol.Name;
|
||||
propertyType = propertySymbol.Type;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return GenerateSerializableProperty(
|
||||
compilation,
|
||||
propertyName,
|
||||
propertyType,
|
||||
order,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
parentSymbol,
|
||||
serializableFieldSaveFlagMethods
|
||||
);
|
||||
}
|
||||
|
||||
public static SerializableProperty GenerateSerializableProperty(
|
||||
Compilation compilation,
|
||||
string propertyName,
|
||||
ISymbol propertyType,
|
||||
int order,
|
||||
ImmutableArray<AttributeData> attributes,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes,
|
||||
ISymbol? parentSymbol,
|
||||
SerializableFieldSaveFlagMethods? serializableFieldSaveFlagMethods
|
||||
)
|
||||
{
|
||||
foreach (var rule in Rules.Values)
|
||||
{
|
||||
if (rule.GenerateRuleState(
|
||||
compilation,
|
||||
propertyType,
|
||||
attributes,
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes,
|
||||
parentSymbol,
|
||||
out var ruleArguments
|
||||
))
|
||||
{
|
||||
return new SerializableProperty
|
||||
{
|
||||
Name = propertyName,
|
||||
Type = propertyType.ToDisplayString(),
|
||||
Order = order,
|
||||
UsesSaveFlag = serializableFieldSaveFlagMethods?.DetermineFieldShouldSerialize != null ? true : null,
|
||||
Rule = rule.RuleName,
|
||||
RuleArguments = ruleArguments.Length > 0 ? ruleArguments : null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"No rule found for property {propertyName} of type {propertyType} ({Rules.Count})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableMigrationSchema.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializableMigration
|
||||
{
|
||||
public static class SerializableMigrationSchema
|
||||
{
|
||||
public static JsonSerializerOptions GetJsonSerializerOptions() =>
|
||||
new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
AllowTrailingCommas = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
private static Dictionary<string, SerializableMetadata> _cache = new();
|
||||
|
||||
private static readonly Regex _fileRegex = new(@"\S+\.v\d+\.json$");
|
||||
|
||||
public static List<SerializableMetadata> GetMigrations(
|
||||
INamedTypeSymbol typeSymbol,
|
||||
int version,
|
||||
string migrationPath,
|
||||
JsonSerializerOptions options
|
||||
)
|
||||
{
|
||||
var typeName = typeSymbol.ToDisplayString();
|
||||
var migrations = new SortedSet<SerializableMetadata>(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<SerializableMetadata>(text, options);
|
||||
_cache[fi.Name] = migration;
|
||||
}
|
||||
|
||||
if (typeName == migration!.Type && version > migration.Version)
|
||||
{
|
||||
migrations.Add(migration);
|
||||
}
|
||||
}
|
||||
|
||||
return migrations.ToList();
|
||||
}
|
||||
|
||||
public static List<SerializableMetadata> GetMigrationsByAnalyzerConfig(
|
||||
this GeneratorExecutionContext context,
|
||||
INamedTypeSymbol typeSymbol,
|
||||
int version,
|
||||
JsonSerializerOptions options
|
||||
)
|
||||
{
|
||||
var typeName = typeSymbol.ToDisplayString();
|
||||
var migrations = new SortedSet<SerializableMetadata>(new SerializableMetadataComparer());
|
||||
|
||||
foreach (var additionalText in context.AdditionalFiles)
|
||||
{
|
||||
var fi = new FileInfo(additionalText.Path);
|
||||
if (!_fileRegex.IsMatch(fi.Name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_cache.TryGetValue(fi.Name, out var migration))
|
||||
{
|
||||
var text = additionalText.GetText(context.CancellationToken)?.ToString();
|
||||
if (text == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
migration = JsonSerializer.Deserialize<SerializableMetadata>(text, options);
|
||||
_cache[fi.Name] = migration;
|
||||
}
|
||||
|
||||
if (typeName == migration!.Type && version > migration.Version)
|
||||
{
|
||||
migrations.Add(migration);
|
||||
}
|
||||
}
|
||||
|
||||
return migrations.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializableProperty.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SerializableMigration
|
||||
{
|
||||
public record SerializableProperty
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; init; }
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; init; }
|
||||
|
||||
[JsonPropertyName("usesSaveFlag")]
|
||||
public bool? UsesSaveFlag { get; init; }
|
||||
|
||||
[JsonPropertyName("rule")]
|
||||
public string Rule { get; init; }
|
||||
|
||||
[JsonPropertyName("ruleArguments")]
|
||||
public string[]? RuleArguments { get; init; }
|
||||
|
||||
[JsonIgnore]
|
||||
public int Order { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SerializablePropertyComparer.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SerializableMigration
|
||||
{
|
||||
public class SerializablePropertyComparer : IComparer<SerializableProperty>
|
||||
{
|
||||
public int Compare(SerializableProperty x, SerializableProperty y)
|
||||
{
|
||||
if (Equals(x, y))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Equals(null, y))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Equals(null, x))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return x.Order.CompareTo(y.Order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<BuildOutputTargetFolder>analyzers</BuildOutputTargetFolder>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.13.14" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Text.Json" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Text.Encodings.Web" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="GetDependencyTargetPaths">
|
||||
<ItemGroup>
|
||||
<TargetPathWithTargetPlatformMoniker Include="$(PKGHumanizer_Core)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
|
||||
<TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Text_Json)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
|
||||
<TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Text_Encodings_Web)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
|
||||
<TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Bcl_AsyncInterfaces)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
|
||||
<TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Runtime_CompilerServices_Unsafe)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SyntaxReceiver.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public class SerializerSyntaxReceiver : ISyntaxContextReceiver
|
||||
{
|
||||
#pragma warning disable RS1024
|
||||
public Dictionary<INamedTypeSymbol, (AttributeData?, List<ISymbol>)> ClassAndFields { get; } = new(SymbolEqualityComparer.Default);
|
||||
public Dictionary<INamedTypeSymbol, (AttributeData?, List<ISymbol>)> EmbeddedClassAndFields { get; } = new(SymbolEqualityComparer.Default);
|
||||
#pragma warning restore RS1024
|
||||
|
||||
public ImmutableArray<INamedTypeSymbol> SerializableList => ClassAndFields.Keys.ToImmutableArray();
|
||||
|
||||
public ImmutableArray<INamedTypeSymbol> EmbeddedSerializableList => EmbeddedClassAndFields.Keys.ToImmutableArray();
|
||||
|
||||
public void OnVisitSyntaxNode(SyntaxNode node, SemanticModel semanticModel)
|
||||
{
|
||||
var compilation = semanticModel.Compilation;
|
||||
|
||||
if (node is ClassDeclarationSyntax { AttributeLists: { Count: > 0 } } classDeclarationSyntax)
|
||||
{
|
||||
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (classSymbol.IsEmbeddedSerializable(compilation, out var attrData))
|
||||
{
|
||||
if (EmbeddedClassAndFields.TryGetValue(classSymbol, out var value))
|
||||
{
|
||||
var (_, fieldsList) = value;
|
||||
EmbeddedClassAndFields[classSymbol] = (attrData, fieldsList);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmbeddedClassAndFields.Add(classSymbol, (attrData, new List<ISymbol>()));
|
||||
}
|
||||
}
|
||||
else if (classSymbol.WillBeSerializable(compilation, out attrData))
|
||||
{
|
||||
if (ClassAndFields.TryGetValue(classSymbol, out var value))
|
||||
{
|
||||
var (_, fieldsList) = value;
|
||||
ClassAndFields[classSymbol] = (attrData, fieldsList);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassAndFields.Add(classSymbol, (attrData, new List<ISymbol>()));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (node is FieldDeclarationSyntax { AttributeLists: { Count: > 0 } } fieldDeclarationSyntax)
|
||||
{
|
||||
foreach (var variable in fieldDeclarationSyntax.Declaration.Variables)
|
||||
{
|
||||
if (semanticModel.GetDeclaredSymbol(variable) is IFieldSymbol fieldSymbol)
|
||||
{
|
||||
AddFieldOrProperty(fieldSymbol, compilation);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (node is PropertyDeclarationSyntax { AttributeLists: { Count: > 0 } } propertyDeclarationSyntax)
|
||||
{
|
||||
if (semanticModel.GetDeclaredSymbol(propertyDeclarationSyntax) is IPropertySymbol propertySymbol)
|
||||
{
|
||||
AddFieldOrProperty(propertySymbol, compilation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnVisitSyntaxNode(GeneratorSyntaxContext context) =>
|
||||
OnVisitSyntaxNode(context.Node, context.SemanticModel);
|
||||
|
||||
private void AddFieldOrProperty(ISymbol symbol, Compilation compilation)
|
||||
{
|
||||
var serializableFieldAttr = compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_FIELD_ATTRIBUTE);
|
||||
var parentAttr = compilation.GetTypeByMetadataName(SymbolMetadata.SERIALIZABLE_PARENT_ATTRIBUTE);
|
||||
|
||||
if (symbol.GetAttribute(serializableFieldAttr) == null && symbol.GetAttribute(parentAttr) == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var classSymbol = symbol.ContainingType;
|
||||
if (ClassAndFields.TryGetValue(classSymbol, out var value))
|
||||
{
|
||||
var (_, fieldsList) = value;
|
||||
fieldsList.Add(symbol);
|
||||
return;
|
||||
}
|
||||
|
||||
if (EmbeddedClassAndFields.TryGetValue(classSymbol, out value))
|
||||
{
|
||||
var (_, fieldsList) = value;
|
||||
fieldsList.Add(symbol);
|
||||
return;
|
||||
}
|
||||
|
||||
if (classSymbol.WillBeSerializable(compilation, out var attrData))
|
||||
{
|
||||
ClassAndFields.Add(classSymbol, (attrData, new List<ISymbol> { symbol }));
|
||||
}
|
||||
else if (classSymbol.IsEmbeddedSerializable(compilation, out attrData))
|
||||
{
|
||||
EmbeddedClassAndFields.Add(classSymbol, (attrData, new List<ISymbol> { symbol }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: Helpers.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static class Helpers
|
||||
{
|
||||
public static bool ContainsInterface(this ITypeSymbol symbol, ISymbol interfaceSymbol) =>
|
||||
symbol.Interfaces.Any(i => i.ConstructedFrom.Equals(interfaceSymbol, SymbolEqualityComparer.Default)) ||
|
||||
symbol.AllInterfaces.Any(i => i.ConstructedFrom.Equals(interfaceSymbol, SymbolEqualityComparer.Default));
|
||||
|
||||
public static ImmutableArray<IMethodSymbol> GetAllMethods(this ITypeSymbol symbol, string name)
|
||||
{
|
||||
var methods = symbol.GetMembers(name).OfType<IMethodSymbol>().ToImmutableArray();
|
||||
if (symbol.ContainingSymbol is not ITypeSymbol typeSymbol)
|
||||
{
|
||||
return methods;
|
||||
}
|
||||
|
||||
var list = new List<IMethodSymbol>();
|
||||
list.AddRange(methods.ToList());
|
||||
list.AddRange(GetAllMethods(typeSymbol, name).ToList());
|
||||
|
||||
return list.ToImmutableArray();
|
||||
}
|
||||
|
||||
public static string ToFriendlyString(this Accessibility accessibility) => SyntaxFacts.GetText(accessibility);
|
||||
|
||||
public static Accessibility GetAccessibility(string? value) =>
|
||||
value switch
|
||||
{
|
||||
"private" => Accessibility.Private,
|
||||
"protected" => Accessibility.Protected,
|
||||
"internal" => Accessibility.Internal,
|
||||
"public" => Accessibility.Public,
|
||||
"protected internal" => Accessibility.ProtectedOrInternal,
|
||||
"private protected" => Accessibility.ProtectedAndInternal,
|
||||
_ => Accessibility.NotApplicable
|
||||
};
|
||||
|
||||
public static bool CanBeConstructedFrom(this ITypeSymbol? symbol, ISymbol classSymbol) =>
|
||||
symbol is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.ConstructedFrom.Equals(
|
||||
classSymbol,
|
||||
SymbolEqualityComparer.Default
|
||||
) || symbol != null && CanBeConstructedFrom(symbol.BaseType, classSymbol);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SourceGeneration.Arguments.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SourceGeneration
|
||||
{
|
||||
public static void GetTypesFromTypedConstant(TypedConstant arg, List<ITypeSymbol> list)
|
||||
{
|
||||
if (arg.Kind == TypedConstantKind.Type)
|
||||
{
|
||||
list.Add((ITypeSymbol)arg.Value);
|
||||
}
|
||||
else if (arg.Kind == TypedConstantKind.Array)
|
||||
{
|
||||
for (var i = 0; i < arg.Values.Length; i++)
|
||||
{
|
||||
GetTypesFromTypedConstant(arg.Values[i], list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void GenerateSignatureArguments(this StringBuilder source, ImmutableArray<(ITypeSymbol, string)> parameters)
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var (t, v) = parameters[i];
|
||||
source.AppendFormat("{0} {1}", t.ToDisplayString(), v);
|
||||
if (i < parameters.Length - 1)
|
||||
{
|
||||
source.Append(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void GenerateNamedArgument(this StringBuilder source, KeyValuePair<string, TypedConstant> namedArg)
|
||||
{
|
||||
source.AppendFormat("{0} = ", namedArg.Key);
|
||||
source.GenerateTypedConstant(namedArg.Value);
|
||||
}
|
||||
|
||||
public static void GenerateTypedConstants(this StringBuilder source, ImmutableArray<TypedConstant> args)
|
||||
{
|
||||
source.Append("new []{");
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
source.GenerateTypedConstant(args[i]);
|
||||
if (i < args.Length - 1)
|
||||
{
|
||||
source.Append(", ");
|
||||
}
|
||||
}
|
||||
source.Append('}');
|
||||
}
|
||||
|
||||
public static void GenerateTypedConstant(this StringBuilder source, TypedConstant arg)
|
||||
{
|
||||
if (arg.IsNull)
|
||||
{
|
||||
source.Append("null");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (arg.Kind)
|
||||
{
|
||||
default:
|
||||
{
|
||||
return;
|
||||
}
|
||||
case TypedConstantKind.Primitive:
|
||||
{
|
||||
|
||||
if (arg.Value is string str)
|
||||
{
|
||||
source.AppendFormat("\"{0}\"", str);
|
||||
}
|
||||
else
|
||||
{
|
||||
source.Append(arg.Value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TypedConstantKind.Enum:
|
||||
{
|
||||
if (arg.Type == null || arg.Value == null)
|
||||
{
|
||||
source.Append("null");
|
||||
}
|
||||
else
|
||||
{
|
||||
source.AppendFormat("({0}){1}", arg.Type.ToDisplayString(), arg.Value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TypedConstantKind.Type:
|
||||
{
|
||||
source.AppendFormat("typeof({0})", ((ITypeSymbol)arg.Value)?.Name);
|
||||
break;
|
||||
}
|
||||
case TypedConstantKind.Array:
|
||||
{
|
||||
source.GenerateTypedConstants(arg.Values);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SourceGeneration.Attribute.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SourceGeneration
|
||||
{
|
||||
public static void GenerateAttribute(
|
||||
this StringBuilder source,
|
||||
string indent,
|
||||
string attrClassName,
|
||||
ImmutableArray<TypedConstant> args
|
||||
)
|
||||
{
|
||||
source.Append($"{indent}[{attrClassName}");
|
||||
var hasArgs = args.Length > 0;
|
||||
|
||||
if (hasArgs)
|
||||
{
|
||||
source.Append("(");
|
||||
}
|
||||
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var arg = args[i];
|
||||
source.GenerateTypedConstant(arg);
|
||||
if (i < args.Length - 1)
|
||||
{
|
||||
source.Append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
if (hasArgs)
|
||||
{
|
||||
source.Append(")");
|
||||
}
|
||||
|
||||
source.AppendLine("]");
|
||||
}
|
||||
|
||||
public static void GenerateAttribute(this StringBuilder source, AttributeData attr)
|
||||
{
|
||||
source.Append($" [{attr.AttributeClass?.Name}");
|
||||
var ctorArgs = attr.ConstructorArguments;
|
||||
var namedArgs = attr.NamedArguments;
|
||||
var hasArgs = ctorArgs.Length + namedArgs.Length > 0;
|
||||
|
||||
if (hasArgs)
|
||||
{
|
||||
source.Append("(");
|
||||
}
|
||||
|
||||
for (var i = 0; i < ctorArgs.Length; i++)
|
||||
{
|
||||
var arg = ctorArgs[i];
|
||||
source.GenerateTypedConstant(arg);
|
||||
if (i < ctorArgs.Length - 1)
|
||||
{
|
||||
source.Append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < namedArgs.Length; i++)
|
||||
{
|
||||
var arg = namedArgs[i];
|
||||
source.GenerateNamedArgument(arg);
|
||||
if (i < namedArgs.Length - 1)
|
||||
{
|
||||
source.Append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
if (hasArgs)
|
||||
{
|
||||
source.Append(")");
|
||||
}
|
||||
|
||||
source.AppendLine("]");
|
||||
}
|
||||
|
||||
public static void AggressiveInline(this StringBuilder source, string indent) =>
|
||||
source.AppendLine(
|
||||
$"{indent}[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SourceGeneration.Class.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SourceGeneration
|
||||
{
|
||||
public static void GenerateClassStart(
|
||||
this StringBuilder source,
|
||||
INamedTypeSymbol classSymbol,
|
||||
string indent,
|
||||
ImmutableArray<ITypeSymbol> interfaces,
|
||||
bool isPartial = true
|
||||
)
|
||||
{
|
||||
var accessor = classSymbol.DeclaredAccessibility;
|
||||
source.Append($"{indent}{accessor.ToFriendlyString()} {(isPartial ? "partial " : "")}class {classSymbol.Name}");
|
||||
if (!interfaces.IsEmpty)
|
||||
{
|
||||
source.Append(" : ");
|
||||
for (var i = 0; i < interfaces.Length; i++)
|
||||
{
|
||||
source.Append(interfaces[i].ToDisplayString());
|
||||
if (i < interfaces.Length - 1)
|
||||
{
|
||||
source.Append(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source.AppendLine($"\n{indent}{{");
|
||||
}
|
||||
|
||||
public static void GenerateClassEnd(this StringBuilder source, string indent)
|
||||
{
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
|
||||
// TODO: Generalize this to any field using dynamic indentation
|
||||
public static void GenerateClassField(
|
||||
this StringBuilder source,
|
||||
string indent,
|
||||
Accessibility accessors,
|
||||
InstanceModifier instance,
|
||||
string type,
|
||||
string variableName,
|
||||
string value
|
||||
)
|
||||
{
|
||||
var instanceStr = instance == InstanceModifier.None ? "" : $"{instance.ToFriendlyString()} ";
|
||||
var accessorStr = accessors == Accessibility.NotApplicable ? "" : $"{accessors.ToFriendlyString()} ";
|
||||
var valueStr = value == null ? "" : $" = {value}";
|
||||
source.AppendLine($"{indent}{accessorStr}{instanceStr}{type} {variableName}{valueStr};");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SourceGeneration.Enum.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SourceGeneration
|
||||
{
|
||||
public static void GenerateEnumStart(
|
||||
this StringBuilder source,
|
||||
string enumName,
|
||||
string indent,
|
||||
bool useFlags,
|
||||
Accessibility accessor = Accessibility.Public
|
||||
)
|
||||
{
|
||||
if (useFlags)
|
||||
{
|
||||
source.AppendLine($"{indent}[System.Flags]");
|
||||
}
|
||||
source.AppendLine($"{indent}{accessor.ToFriendlyString()} enum {enumName}\n{indent}{{");
|
||||
}
|
||||
|
||||
public static void GenerateEnumValue(this StringBuilder source, string indent, bool isFlag, string name, int value)
|
||||
{
|
||||
var number = value < 0 ? 0 : 1 << value;
|
||||
var valueStr = isFlag ? $"0x{number:X8}" : value.ToString();
|
||||
source.AppendLine($"{indent}{name} = {valueStr},");
|
||||
}
|
||||
|
||||
public static void GenerateEnumEnd(this StringBuilder source, string indent)
|
||||
{
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SourceGeneration.InstanceModifier.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public enum InstanceModifier
|
||||
{
|
||||
None,
|
||||
Const,
|
||||
ReadOnly,
|
||||
Static,
|
||||
StaticReadOnly
|
||||
}
|
||||
|
||||
public static partial class SourceGeneration
|
||||
{
|
||||
public static string ToFriendlyString(this InstanceModifier modifier) =>
|
||||
modifier switch
|
||||
{
|
||||
InstanceModifier.Const => "const",
|
||||
InstanceModifier.ReadOnly => "readonly",
|
||||
InstanceModifier.Static => "static",
|
||||
InstanceModifier.StaticReadOnly => "static readonly",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SourceGeneration.Method.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SourceGeneration
|
||||
{
|
||||
public static void GenerateMethodStart(
|
||||
this StringBuilder source, string indent, string methodName, Accessibility accessors, bool isOverride,
|
||||
string returnType, ImmutableArray<(ITypeSymbol, string)> parameters
|
||||
)
|
||||
{
|
||||
source.Append($"{indent}{accessors.ToFriendlyString()}{(isOverride ? " override" : "")} {returnType} {methodName}(");
|
||||
source.GenerateSignatureArguments(parameters);
|
||||
source.AppendLine($")\n{indent}{{");
|
||||
}
|
||||
|
||||
public static void GenerateMethodEnd(this StringBuilder source, string indent) => source.AppendLine($"{indent}}}");
|
||||
|
||||
public static void GenerateConstructorStart(
|
||||
this StringBuilder source, string indent, string className, Accessibility accessors, ImmutableArray<(ITypeSymbol, string)> parameters,
|
||||
ImmutableArray<string> baseParameters, bool isOverload = false
|
||||
)
|
||||
{
|
||||
source.Append($"{indent}{accessors.ToFriendlyString()} {className}(");
|
||||
source.GenerateSignatureArguments(parameters);
|
||||
source.Append(')');
|
||||
bool hasBaseParams = baseParameters.Length > 0;
|
||||
if (hasBaseParams)
|
||||
{
|
||||
source.AppendFormat(" : {0}(", isOverload ? "this" : "base");
|
||||
for (int i = 0; i < baseParameters.Length; i++)
|
||||
{
|
||||
source.Append(baseParameters[i]);
|
||||
if (i < baseParameters.Length - 1)
|
||||
{
|
||||
source.Append(',');
|
||||
}
|
||||
}
|
||||
source.Append(')');
|
||||
}
|
||||
|
||||
source.AppendLine($"\n{indent}{{");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SourceGeneration.Namespace.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SourceGeneration
|
||||
{
|
||||
public static void GenerateNamespaceStart(this StringBuilder source, string namespaceName)
|
||||
{
|
||||
source.AppendLine($@"namespace {namespaceName}
|
||||
{{");
|
||||
}
|
||||
|
||||
public static void GenerateNamespaceEnd(this StringBuilder source)
|
||||
{
|
||||
source.AppendLine("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright (C) 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SourceGeneration.Property.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using Humanizer;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SourceGeneration
|
||||
{
|
||||
public static string GetPropertyName(this IFieldSymbol fieldSymbol)
|
||||
{
|
||||
var fieldName = fieldSymbol.Name;
|
||||
|
||||
var propertyName = fieldName;
|
||||
|
||||
if (propertyName.StartsWith("m_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
propertyName = propertyName.Substring(2);
|
||||
}
|
||||
else if (propertyName.StartsWith("_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
propertyName = propertyName.Substring(1);
|
||||
}
|
||||
|
||||
return propertyName.Dehumanize();
|
||||
}
|
||||
|
||||
public static void GeneratePropertyStart(
|
||||
this StringBuilder source,
|
||||
string indent,
|
||||
Accessibility accessors,
|
||||
bool isVirtual,
|
||||
IFieldSymbol fieldSymbol
|
||||
)
|
||||
{
|
||||
var propertyName = fieldSymbol.GetPropertyName();
|
||||
var virt = isVirtual ? "virtual " : "";
|
||||
|
||||
source.AppendLine($"{indent}{accessors.ToFriendlyString()} {virt}{fieldSymbol.Type} {propertyName}");
|
||||
source.AppendLine($"{indent}{{");
|
||||
}
|
||||
|
||||
public static void GenerateAutoProperty(
|
||||
this StringBuilder source,
|
||||
Accessibility accessors,
|
||||
string type,
|
||||
string propertyName,
|
||||
Accessibility? getAccessor,
|
||||
Accessibility? setAccessor,
|
||||
string indent,
|
||||
bool useInit = false,
|
||||
string defaultValue = null,
|
||||
bool isOverride = false
|
||||
)
|
||||
{
|
||||
if (getAccessor == null && setAccessor == null)
|
||||
{
|
||||
throw new ArgumentNullException($"Must specify a {nameof(getAccessor)} or {nameof(setAccessor)} parameter");
|
||||
}
|
||||
|
||||
var getter = getAccessor == null ?
|
||||
"" :
|
||||
$"{(getAccessor != Accessibility.NotApplicable ? $"{getAccessor.Value.ToFriendlyString()} " : "")}get;";
|
||||
|
||||
var getterSpace = getAccessor != null ? " " : "";
|
||||
var setOrInit = useInit ? "init;" : "set;";
|
||||
|
||||
var setterAccessor = setAccessor is null or Accessibility.NotApplicable
|
||||
? ""
|
||||
: $"{setAccessor.Value.ToFriendlyString() ?? ""} ";
|
||||
|
||||
var setter = setAccessor == null ? "" : $"{getterSpace}{setterAccessor}{setOrInit}";
|
||||
|
||||
var propertyAccessor = accessors == Accessibility.NotApplicable ? "" : $"{accessors.ToFriendlyString()} ";
|
||||
var printOverride = isOverride ? "override " : "";
|
||||
var printDefaultValue = defaultValue != null ? $"{(setAccessor != null ? " =" : "")} {defaultValue};" : "";
|
||||
var printGetterSetter = setAccessor == null ? "=>" : $"{{ {getter}{setter} }}";
|
||||
|
||||
source.AppendLine($"{indent}{propertyAccessor}{printOverride}{type} {propertyName} {printGetterSetter}{printDefaultValue}");
|
||||
}
|
||||
|
||||
public static void GeneratePropertyEnd(this StringBuilder source, string indent) => source.AppendLine($"{indent}}}");
|
||||
|
||||
public static void GeneratePropertyGetterReturnsField(
|
||||
this StringBuilder source,
|
||||
string indent,
|
||||
IFieldSymbol fieldSymbol,
|
||||
Accessibility Accessibility
|
||||
)
|
||||
{
|
||||
var accessor = Accessibility != Accessibility.NotApplicable ? $"{Accessibility.ToFriendlyString()} " : "";
|
||||
source.AppendLine($"{indent}{accessor}get => {fieldSymbol.Name};");
|
||||
}
|
||||
|
||||
public static void GeneratePropertyGetterStart(
|
||||
this StringBuilder source,
|
||||
string indent,
|
||||
bool useExpression,
|
||||
Accessibility Accessibility
|
||||
)
|
||||
{
|
||||
var accessor = Accessibility != Accessibility.NotApplicable ? $"{Accessibility.ToFriendlyString()} " : "";
|
||||
var expression = useExpression ? " => " : $"\n{indent}{{";
|
||||
source.AppendLine($"{indent}{accessor}get{expression}");
|
||||
}
|
||||
|
||||
public static void GeneratePropertyGetSetEnd(this StringBuilder source, string indent, bool useExpression)
|
||||
{
|
||||
if (!useExpression)
|
||||
{
|
||||
source.AppendLine($"{indent}}}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void GeneratePropertySetterStart(
|
||||
this StringBuilder source,
|
||||
string indent,
|
||||
bool useExpression,
|
||||
Accessibility Accessibility,
|
||||
bool useInit = false
|
||||
)
|
||||
{
|
||||
var init = useInit ? "init" : "set";
|
||||
var expression = useExpression ? " => " : $"\n{indent}{{";
|
||||
var accessor = Accessibility != Accessibility.NotApplicable ? $"{Accessibility.ToFriendlyString()} " : "";
|
||||
source.AppendLine($"{indent}{accessor}{init}{expression}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SymbolMetadata.Builtin.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SymbolMetadata
|
||||
{
|
||||
public const string DICTIONARY_CLASS = "System.Collections.Generic.Dictionary`2";
|
||||
public const string LIST_CLASS = "System.Collections.Generic.List`1";
|
||||
public const string HASHSET_CLASS = "System.Collections.Generic.HashSet`1";
|
||||
public const string IPADDRESS_CLASS = "System.Net.IPAddress";
|
||||
public const string KEYVALUEPAIR_STRUCT = "System.Collections.Generic.KeyValuePair";
|
||||
public const string TIMESPAN_STRUCT = "System.TimeSpan";
|
||||
|
||||
public static bool IsTimeSpan(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(TIMESPAN_STRUCT),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static bool IsIpAddress(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(IPADDRESS_CLASS),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static bool IsKeyValuePair(this ISymbol symbol, Compilation compilation) =>
|
||||
(symbol as INamedTypeSymbol)?.ConstructedFrom.Equals(
|
||||
compilation.GetTypeByMetadataName(KEYVALUEPAIR_STRUCT),
|
||||
SymbolEqualityComparer.Default
|
||||
) == true;
|
||||
|
||||
public static bool IsDictionary(this ISymbol symbol, Compilation compilation) =>
|
||||
(symbol as INamedTypeSymbol)?.ConstructedFrom.Equals(
|
||||
compilation.GetTypeByMetadataName(DICTIONARY_CLASS),
|
||||
SymbolEqualityComparer.Default
|
||||
) == true;
|
||||
|
||||
public static bool IsHashSet(this ISymbol symbol, Compilation compilation) =>
|
||||
(symbol as INamedTypeSymbol)?.ConstructedFrom.Equals(
|
||||
compilation.GetTypeByMetadataName(HASHSET_CLASS),
|
||||
SymbolEqualityComparer.Default
|
||||
) == true;
|
||||
|
||||
public static bool IsList(this ISymbol symbol, Compilation compilation) =>
|
||||
(symbol as INamedTypeSymbol)?.ConstructedFrom.Equals(
|
||||
compilation.GetTypeByMetadataName(LIST_CLASS),
|
||||
SymbolEqualityComparer.Default
|
||||
) == true;
|
||||
|
||||
public static bool IsPrimitiveFromTypeDisplayString(string type) =>
|
||||
type is "bool" or "sbyte" or "short" or "int" or "long" or "byte" or "ushort"
|
||||
or "uint" or "ulong" or "float" or "double" or "string" or "decimal";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SymbolMetadata.UO.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static partial class SymbolMetadata
|
||||
{
|
||||
public const string INVALIDATEPROPERTIES_ATTRIBUTE = "Server.InvalidatePropertiesAttribute";
|
||||
public const string AFTERDESERIALIZATION_ATTRIBUTE = "Server.AfterDeserializationAttribute";
|
||||
public const string SERIALIZABLE_ATTRIBUTE = "Server.SerializableAttribute";
|
||||
public const string EMBEDDED_SERIALIZABLE_ATTRIBUTE = "Server.EmbeddedSerializableAttribute";
|
||||
public const string SERIALIZABLE_PARENT_ATTRIBUTE = "Server.SerializableParentAttribute";
|
||||
public const string SERIALIZABLE_FIELD_ATTRIBUTE = "Server.SerializableFieldAttribute";
|
||||
public const string SERIALIZABLE_FIELD_ATTR_ATTRIBUTE = "Server.SerializableFieldAttrAttribute";
|
||||
public const string SERIALIZABLE_INTERFACE = "Server.ISerializable";
|
||||
public const string GENERIC_WRITER_INTERFACE = "Server.IGenericWriter";
|
||||
public const string GENERIC_READER_INTERFACE = "Server.IGenericReader";
|
||||
public const string DELTA_DATE_TIME_ATTRIBUTE = "Server.DeltaDateTimeAttribute";
|
||||
public const string INTERN_STRING_ATTRIBUTE = "Server.InternStringAttribute";
|
||||
public const string ENCODED_INT_ATTRIBUTE = "Server.EncodedIntAttribute";
|
||||
public const string TIDY_ATTRIBUTE = "Server.TidyAttribute";
|
||||
public const string POINT2D_STRUCT = "Server.Point2D";
|
||||
public const string POINT3D_STRUCT = "Server.Point3D";
|
||||
public const string RECTANGLE2D_STRUCT = "Server.Rectangle2D";
|
||||
public const string RECTANGLE3D_STRUCT = "Server.Rectangle3D";
|
||||
public const string RACE_CLASS = "Server.Race";
|
||||
public const string MAP_CLASS = "Server.Map";
|
||||
public const string TIMER_CLASS = "Server.Timer";
|
||||
public const string TIMER_DRIFT_ATTRIBUTE = "Server.TimerDriftAttribute";
|
||||
public const string DESERIALIZE_TIMER_FIELD_ATTRIBUTE = "Server.DeserializeTimerFieldAttribute";
|
||||
public const string SERIALIZABLE_FIELD_SAVE_FLAG_ATTRIBUTE = "Server.SerializableFieldSaveFlagAttribute";
|
||||
public const string SERIALIZABLE_FIELD_DEFAULT_ATTRIBUTE = "Server.SerializableFieldDefaultAttribute";
|
||||
public const string RAW_SERIALIZABLE_INTERFACE = "Server.IRawSerializable";
|
||||
// ModernUO modified BitArray
|
||||
public const string SERVER_BITARRAY_CLASS = "Server.Collections.BitArray";
|
||||
|
||||
public static bool IsTimerDrift(this AttributeData attr, Compilation compilation) =>
|
||||
attr?.IsAttribute(compilation.GetTypeByMetadataName(TIMER_DRIFT_ATTRIBUTE)) == true;
|
||||
|
||||
public static bool IsTimer(this ITypeSymbol symbol, Compilation compilation) =>
|
||||
symbol.CanBeConstructedFrom(compilation.GetTypeByMetadataName(TIMER_CLASS));
|
||||
|
||||
public static bool IsEncodedInt(this AttributeData attr, Compilation compilation) =>
|
||||
attr?.IsAttribute(compilation.GetTypeByMetadataName(ENCODED_INT_ATTRIBUTE)) == true;
|
||||
|
||||
public static bool IsDeltaDateTime(this AttributeData attr, Compilation compilation) =>
|
||||
attr?.IsAttribute(compilation.GetTypeByMetadataName(DELTA_DATE_TIME_ATTRIBUTE)) == true;
|
||||
|
||||
public static bool IsInternString(this AttributeData attr, Compilation compilation) =>
|
||||
attr?.IsAttribute(compilation.GetTypeByMetadataName(INTERN_STRING_ATTRIBUTE)) == true;
|
||||
|
||||
public static bool IsTidy(this AttributeData attr, Compilation compilation) =>
|
||||
attr?.IsAttribute(compilation.GetTypeByMetadataName(TIDY_ATTRIBUTE)) == true;
|
||||
|
||||
public static bool IsAttribute(this AttributeData attr, ISymbol symbol) =>
|
||||
attr?.AttributeClass?.Equals(symbol, SymbolEqualityComparer.Default) == true;
|
||||
|
||||
public static bool IsEnum(this ITypeSymbol symbol) =>
|
||||
symbol.SpecialType == SpecialType.System_Enum || symbol.TypeKind == TypeKind.Enum;
|
||||
|
||||
public static bool HasSerializableInterface(
|
||||
this ITypeSymbol symbol,
|
||||
Compilation compilation,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes
|
||||
) =>
|
||||
symbol.ContainsInterface(compilation.GetTypeByMetadataName(SERIALIZABLE_INTERFACE)) ||
|
||||
serializableTypes.Contains(symbol);
|
||||
|
||||
public static bool HasRawSerializableInterface(
|
||||
this ITypeSymbol symbol,
|
||||
Compilation compilation,
|
||||
ImmutableArray<INamedTypeSymbol> embeddedSerializableTypes
|
||||
) =>
|
||||
symbol.ContainsInterface(compilation.GetTypeByMetadataName(RAW_SERIALIZABLE_INTERFACE)) ||
|
||||
embeddedSerializableTypes.Contains(symbol);
|
||||
|
||||
public static bool Contains(this ImmutableArray<INamedTypeSymbol> symbols, ITypeSymbol? symbol) =>
|
||||
symbol is INamedTypeSymbol namedSymbol &&
|
||||
symbols.Contains(namedSymbol, SymbolEqualityComparer.Default) || symbols.Contains(symbol?.BaseType);
|
||||
|
||||
public static bool HasGenericReaderCtor(
|
||||
this INamedTypeSymbol symbol,
|
||||
Compilation compilation,
|
||||
ISymbol? parentSymbol,
|
||||
out bool requiresParent
|
||||
)
|
||||
{
|
||||
var genericReaderInterface = compilation.GetTypeByMetadataName(GENERIC_READER_INTERFACE);
|
||||
var genericCtor = symbol.Constructors.FirstOrDefault(
|
||||
m => !m.IsStatic &&
|
||||
m.MethodKind == MethodKind.Constructor &&
|
||||
m.Parameters.Length >= 1 &&
|
||||
m.Parameters.Length <= 2 &&
|
||||
SymbolEqualityComparer.Default.Equals(m.Parameters[0].Type, genericReaderInterface)
|
||||
);
|
||||
|
||||
requiresParent = genericCtor?.Parameters.Length == 2 && SymbolEqualityComparer.Default.Equals(genericCtor.Parameters[1].Type, parentSymbol);
|
||||
return genericCtor != null;
|
||||
}
|
||||
|
||||
public static bool HasPublicSerializeMethod(
|
||||
this ITypeSymbol symbol,
|
||||
Compilation compilation,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes
|
||||
)
|
||||
{
|
||||
var genericWriterInterface = compilation.GetTypeByMetadataName(GENERIC_WRITER_INTERFACE);
|
||||
|
||||
return symbol.GetAllMethods("Serialize")
|
||||
.Any(
|
||||
m => !m.IsStatic &&
|
||||
m.ReturnsVoid &&
|
||||
m.Parameters.Length == 1 &&
|
||||
SymbolEqualityComparer.Default.Equals(m.Parameters[0].Type, genericWriterInterface) &&
|
||||
m.DeclaredAccessibility == Accessibility.Public
|
||||
);
|
||||
}
|
||||
|
||||
public static bool HasPublicDeserializeMethod(
|
||||
this ITypeSymbol symbol,
|
||||
Compilation compilation,
|
||||
ImmutableArray<INamedTypeSymbol> serializableTypes
|
||||
)
|
||||
{
|
||||
var genericReaderInterface = compilation.GetTypeByMetadataName(GENERIC_READER_INTERFACE);
|
||||
|
||||
return symbol.GetAllMethods("Deserialize")
|
||||
.Any(
|
||||
m => !m.IsStatic &&
|
||||
m.ReturnsVoid &&
|
||||
m.Parameters.Length == 1 &&
|
||||
SymbolEqualityComparer.Default.Equals(m.Parameters[0].Type, genericReaderInterface) &&
|
||||
m.DeclaredAccessibility == Accessibility.Public
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsPoint2D(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(POINT2D_STRUCT),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static bool IsPoint3D(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(POINT3D_STRUCT),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static bool IsRectangle2D(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(RECTANGLE2D_STRUCT),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static bool IsRectangle3D(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(RECTANGLE3D_STRUCT),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static bool IsRace(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(RACE_CLASS),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static bool IsMap(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(MAP_CLASS),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static bool IsBitArray(this ISymbol symbol, Compilation compilation) =>
|
||||
symbol.Equals(
|
||||
compilation.GetTypeByMetadataName(SERVER_BITARRAY_CLASS),
|
||||
SymbolEqualityComparer.Default
|
||||
);
|
||||
|
||||
public static AttributeData? GetAttribute(this ISymbol symbol, ISymbol attrSymbol) =>
|
||||
symbol
|
||||
.GetAttributes()
|
||||
.FirstOrDefault(
|
||||
ad => ad.AttributeClass != null && SymbolEqualityComparer.Default.Equals(ad.AttributeClass, attrSymbol)
|
||||
);
|
||||
|
||||
public static bool WillBeSerializable(this INamedTypeSymbol classSymbol, Compilation compilation, out AttributeData? attributeData)
|
||||
{
|
||||
var serializableInterface = compilation.GetTypeByMetadataName(SERIALIZABLE_INTERFACE);
|
||||
|
||||
if (!classSymbol.ContainsInterface(serializableInterface))
|
||||
{
|
||||
attributeData = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var serializableEntityAttribute =
|
||||
compilation.GetTypeByMetadataName(SERIALIZABLE_ATTRIBUTE);
|
||||
|
||||
attributeData = classSymbol.GetAttribute(serializableEntityAttribute);
|
||||
return attributeData != null;
|
||||
}
|
||||
|
||||
public static bool IsEmbeddedSerializable(this INamedTypeSymbol classSymbol, Compilation compilation, out AttributeData? attributeData)
|
||||
{
|
||||
var embeddedSerializableEntityAttribute =
|
||||
compilation.GetTypeByMetadataName(EMBEDDED_SERIALIZABLE_ATTRIBUTE);
|
||||
|
||||
attributeData = classSymbol.GetAttribute(embeddedSerializableEntityAttribute);
|
||||
return attributeData != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: Utility.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SerializationGenerator
|
||||
{
|
||||
public static class Utility
|
||||
{
|
||||
public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple, out T1 key, out T2 value)
|
||||
{
|
||||
key = tuple.Key;
|
||||
value = tuple.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
Output/
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: Application.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializationSchemaGenerator
|
||||
{
|
||||
public static class Application
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
throw new ArgumentException("Usage: dotnet SerializationSchemaGenerator.dll <path to solution>");
|
||||
}
|
||||
|
||||
var solutionPath = args[0];
|
||||
|
||||
Parallel.ForEach(
|
||||
SourceCodeAnalysis.GetCompilation(solutionPath),
|
||||
(projectCompilation) =>
|
||||
{
|
||||
var (project, compilation) = projectCompilation;
|
||||
if (project.Name.EndsWith(".Tests", StringComparison.Ordinal) || project.Name == "Benchmarks")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var projectFile = new FileInfo(project.FilePath!);
|
||||
var projectPath = projectFile.Directory?.FullName;
|
||||
var migrationPath = Path.Join(projectPath, "Migrations");
|
||||
Directory.CreateDirectory(migrationPath);
|
||||
|
||||
var syntaxReceiver = new SerializerSyntaxReceiver();
|
||||
|
||||
foreach (var syntaxTree in compilation.SyntaxTrees)
|
||||
{
|
||||
var root = syntaxTree.GetRoot();
|
||||
var syntaxVisitor = new SyntaxVisitor(compilation.GetSemanticModel(syntaxTree), syntaxReceiver);
|
||||
syntaxVisitor.Visit(root);
|
||||
}
|
||||
|
||||
var jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
AllowTrailingCommas = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
var serializableTypes = syntaxReceiver.SerializableList;
|
||||
var embeddedSerializableTypes = syntaxReceiver.EmbeddedSerializableList;
|
||||
|
||||
foreach (var (classSymbol, (attributeData, fieldsList)) in syntaxReceiver.ClassAndFields)
|
||||
{
|
||||
var source = compilation.GenerateSerializationPartialClass(
|
||||
classSymbol,
|
||||
attributeData,
|
||||
migrationPath,
|
||||
false,
|
||||
jsonOptions,
|
||||
fieldsList.ToImmutableArray(),
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes
|
||||
);
|
||||
}
|
||||
|
||||
foreach (var (classSymbol, (attributeData, fieldsList)) in syntaxReceiver.EmbeddedClassAndFields)
|
||||
{
|
||||
var source = compilation.GenerateSerializationPartialClass(
|
||||
classSymbol,
|
||||
attributeData,
|
||||
migrationPath,
|
||||
true,
|
||||
jsonOptions,
|
||||
fieldsList.ToImmutableArray(),
|
||||
serializableTypes,
|
||||
embeddedSerializableTypes
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<OutDir>Output</OutDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SerializationGenerator\SerializationGenerator.csproj">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.13.14" />
|
||||
<PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.0.1" />
|
||||
<PackageReference Include="System.Text.Json" Version="6.0.0" />
|
||||
<PackageReference Include="System.Text.Encodings.Web" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SourceCodeAnalysis.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Locator;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.MSBuild;
|
||||
|
||||
namespace SerializationSchemaGenerator
|
||||
{
|
||||
public static class SourceCodeAnalysis
|
||||
{
|
||||
public static List<(Project, Compilation)> GetCompilation(string solutionPath)
|
||||
{
|
||||
if (!File.Exists(solutionPath) || !solutionPath.EndsWith(".sln", StringComparison.Ordinal))
|
||||
{
|
||||
throw new FileNotFoundException($"Could not open a valid solution at location {solutionPath}");
|
||||
}
|
||||
|
||||
MSBuildLocator.RegisterDefaults();
|
||||
|
||||
var workspace = MSBuildWorkspace.Create();
|
||||
|
||||
var solutionToAnalyze = workspace.OpenSolutionAsync(solutionPath).Result;
|
||||
|
||||
var results = solutionToAnalyze.Projects.AsParallel()
|
||||
.Select((project) => (project, project?.GetCompilationAsync().Result))
|
||||
.Where((value) => value.Result != null)
|
||||
.ToList();
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2021 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: SyntaxVisitor.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using SerializationGenerator;
|
||||
|
||||
namespace SerializationSchemaGenerator
|
||||
{
|
||||
public class SyntaxVisitor : CSharpSyntaxWalker
|
||||
{
|
||||
private readonly SemanticModel _semanticModel;
|
||||
private readonly SerializerSyntaxReceiver _syntaxReceiver;
|
||||
|
||||
public SyntaxVisitor(SemanticModel semanticModel, SerializerSyntaxReceiver syntaxReceiver)
|
||||
{
|
||||
_semanticModel = semanticModel;
|
||||
_syntaxReceiver = syntaxReceiver;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,14 +37,8 @@
|
|||
<PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.1.2" />
|
||||
<PackageReference Include="PollGroup" Version="1.1.0" />
|
||||
<PackageReference Include="Zlib.Bindings" Version="1.8.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SerializationGenerator\SerializationGenerator.csproj">
|
||||
<SetTargetFramework>TargetFramework=netstandard2.0</SetTargetFramework>
|
||||
<OutputItemType>Analyzer</OutputItemType>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</ProjectReference>
|
||||
|
||||
<PackageReference Include="ModernUO.SerializationGenerator" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="Migrations/*.v*.json" />
|
||||
|
|
|
|||
|
|
@ -38,20 +38,14 @@
|
|||
<ProjectReference Include="..\Server\Server.csproj" Private="false" PrivateAssets="All" IncludeAssets="None">
|
||||
<IncludeInPackage>false</IncludeInPackage>
|
||||
</ProjectReference>
|
||||
<PackageReference Include="MailKit" Version="3.0.0" />
|
||||
<PackageReference Include="MailKit" Version="3.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.1.2" />
|
||||
<PackageReference Include="Zlib.Bindings" Version="1.8.0" />
|
||||
<PackageReference Include="Argon2.Bindings" Version="1.12.0" />
|
||||
<PackageReference Include="Zstd.Binaries" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SerializationGenerator\SerializationGenerator.csproj">
|
||||
<SetTargetFramework>TargetFramework=netstandard2.0</SetTargetFramework>
|
||||
<OutputItemType>Analyzer</OutputItemType>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</ProjectReference>
|
||||
|
||||
<PackageReference Include="ModernUO.SerializationGenerator" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="Migrations/*.v*.json" />
|
||||
|
|
|
|||
24
publish.cmd
24
publish.cmd
|
|
@ -27,21 +27,19 @@ if [[ $os == *'centos'* || $os == *'rhel'* ]]; then
|
|||
export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||
fi
|
||||
|
||||
echo dotnet tool restore
|
||||
dotnet tool restore
|
||||
|
||||
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 build -c Release Projects/SerializationGenerator/SerializationGenerator.csproj
|
||||
dotnet build -c Release Projects/SerializationGenerator/SerializationGenerator.csproj
|
||||
|
||||
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
|
||||
dotnet Projects/SerializationSchemaGenerator/Output/SerializationSchemaGenerator.dll ModernUO.sln
|
||||
echo Generating serialization migration schema...
|
||||
dotnet tool run ModernUOSchemaGenerator ModernUO.sln
|
||||
|
||||
exit $?
|
||||
|
||||
|
|
@ -63,18 +61,16 @@ IF "%~2" == "" (
|
|||
SET os=-r %~2-x64
|
||||
)
|
||||
|
||||
echo dotnet tool restore
|
||||
dotnet tool restore
|
||||
|
||||
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 build -c Release Projects/SerializationGenerator/SerializationGenerator.csproj
|
||||
dotnet build -c Release Projects/SerializationGenerator/SerializationGenerator.csproj
|
||||
|
||||
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
|
||||
dotnet Projects/SerializationSchemaGenerator/Output/SerializationSchemaGenerator.dll ModernUO.sln
|
||||
echo Generating serialization migration schema...
|
||||
dotnet tool run ModernUOSchemaGenerator ModernUO.sln
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue