Merge remote-tracking branch 'origin/alchemy-serialize-with-inheritance' into alchemy-serialize-with-inheritance

# Conflicts:
#	Alchemy.SourceGenerator/AlchemySerializeGenerator.cs
This commit is contained in:
Akeit0 2024-03-03 13:12:04 +09:00
commit cb32709324

View File

@ -26,22 +26,26 @@ namespace Alchemy.SourceGenerator
{ {
foreach (var typeSyntax in receiver.TargetTypes) foreach (var typeSyntax in receiver.TargetTypes)
{ {
var typeSymbol = context.Compilation.GetSemanticModel(typeSyntax.SyntaxTree).GetDeclaredSymbol(typeSyntax); var typeSymbol = context.Compilation.GetSemanticModel(typeSyntax.SyntaxTree)
.GetDeclaredSymbol(typeSyntax);
if (!IsPartial(typeSyntax)) if (!IsPartial(typeSyntax))
{ {
context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.MustBePartial, typeSyntax.Identifier.GetLocation(), typeSymbol.Name)); context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.MustBePartial,
typeSyntax.Identifier.GetLocation(), typeSymbol.Name));
continue; continue;
} }
if (IsNested(typeSyntax)) if (IsNested(typeSyntax))
{ {
context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.NestedNotAllow, typeSyntax.Identifier.GetLocation(), typeSymbol.Name)); context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.NestedNotAllow,
typeSyntax.Identifier.GetLocation(), typeSymbol.Name));
continue; continue;
} }
var fieldSymbols = new List<IFieldSymbol>(); var fieldSymbols = new List<IFieldSymbol>();
var fields = typeSyntax.Members.OfType<FieldDeclarationSyntax>(); var fields = typeSyntax.Members
.OfType<FieldDeclarationSyntax>();
foreach (var field in fields) foreach (var field in fields)
{ {
var model = context.Compilation.GetSemanticModel(field.SyntaxTree); var model = context.Compilation.GetSemanticModel(field.SyntaxTree);
@ -51,22 +55,24 @@ namespace Alchemy.SourceGenerator
var alchemySerializeAttribute = fieldSymbol.GetAttributes() var alchemySerializeAttribute = fieldSymbol.GetAttributes()
.FirstOrDefault(x => .FirstOrDefault(x =>
x.AttributeClass.Name is "AlchemySerializeField" x.AttributeClass.Name is "AlchemySerializeField"
or "AlchemySerializeFieldAttribute" or "AlchemySerializeFieldAttribute"
or "Alchemy.Serialization.AlchemySerializeField" or "Alchemy.Serialization.AlchemySerializeField"
or "Alchemy.Serialization.AlchemySerializeFieldAttribute"); or "Alchemy.Serialization.AlchemySerializeFieldAttribute");
var nonSerializedAttribute = fieldSymbol.GetAttributes() var nonSerializedAttribute = fieldSymbol.GetAttributes()
.FirstOrDefault(x => .FirstOrDefault(x =>
x.AttributeClass.Name is "NonSerialized" x.AttributeClass.Name is "NonSerialized"
or "NonSerializedAttribute" or "NonSerializedAttribute"
or "System.NonSerialized" or "System.NonSerialized"
or "System.NonSerializedAttribute"); or "System.NonSerializedAttribute");
if (alchemySerializeAttribute != null) if (alchemySerializeAttribute != null)
{ {
if (nonSerializedAttribute == null) if (nonSerializedAttribute == null)
{ {
context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.ShouldBeNonSerialized, variable.Identifier.GetLocation(), fieldSymbol.Name)); context.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.ShouldBeNonSerialized, variable.Identifier.GetLocation(),
fieldSymbol.Name));
} }
fieldSymbols.Add(fieldSymbol); fieldSymbols.Add(fieldSymbol);
@ -85,14 +91,16 @@ namespace Alchemy.SourceGenerator
} }
catch (Exception ex) catch (Exception ex)
{ {
var diagnosticDescriptor = new DiagnosticDescriptor("AlchemySerializeGeneratorError", "AlchemySerializeGeneratorError", $"Generation failed with:\n {ex}", "AlchemySerializeGeneratorError", DiagnosticSeverity.Error, true); var diagnosticDescriptor = new DiagnosticDescriptor("AlchemySerializeGeneratorError",
context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, Location.None, DiagnosticSeverity.Error)); "AlchemySerializeGeneratorError", $"Generation failed with:\n {ex}",
"AlchemySerializeGeneratorError", DiagnosticSeverity.Error, true);
context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, Location.None,
DiagnosticSeverity.Error));
} }
} }
static string ReplaceGenericsToCount( string typeName,int count)
static string ReplaceGenericsToCount(string typeName, int count)
{ {
if (count == 0) return typeName; if(count == 0) return typeName;
var builder = new StringBuilder(); var builder = new StringBuilder();
bool skip = false; bool skip = false;
foreach (var c in typeName) foreach (var c in typeName)
@ -111,7 +119,6 @@ namespace Alchemy.SourceGenerator
builder.Append(c); builder.Append(c);
} }
} }
return builder.ToString(); return builder.ToString();
} }
@ -124,11 +131,11 @@ namespace Alchemy.SourceGenerator
var baseType = typeSymbol.BaseType; var baseType = typeSymbol.BaseType;
while (baseType != null) while (baseType != null)
{ {
if (baseType.GetAttributes().Any(x => if (baseType.GetAttributes().Any(x => x.AttributeClass!.Name
x.AttributeClass!.Name is "AlchemySerialize" is "AlchemySerialize"
or "AlchemySerializeAttribute" or "AlchemySerializeAttribute"
or "Alchemy.Serialization.AlchemySerialize" or "Alchemy.Serialization.AlchemySerialize"
or "Alchemy.Serialization.AlchemySerializeAttribute")) or "Alchemy.Serialization.AlchemySerializeAttribute"))
{ {
hasInheritedImplementation = true; hasInheritedImplementation = true;
break; break;
@ -141,32 +148,39 @@ namespace Alchemy.SourceGenerator
if (typeSymbol.IsGenericType) if (typeSymbol.IsGenericType)
{ {
genericsCount = typeSymbol.TypeParameters.Length; genericsCount = typeSymbol.TypeParameters.Length;
} }
var typeGenerics = typeSymbol.IsGenericType var typeGenerics = typeSymbol.IsGenericType
? "<" + string.Join(", ", typeSymbol.TypeParameters.Select(x => x.Name)) + ">" ? "<" + string.Join(", ", typeSymbol.TypeParameters.Select(x => x.Name)) + ">"
: ""; : "";
var alchemySerializationDataName = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat).Replace("global::", "").Replace(".", "_"); var alchemySerializationDataName = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
alchemySerializationDataName = ReplaceGenericsToCount(alchemySerializationDataName, genericsCount) + "_alchemySerializationData"; .Replace("global::", "").Replace(".", "_");
alchemySerializationDataName = ReplaceGenericsToCount(alchemySerializationDataName,genericsCount) + "_alchemySerializationData";
var inheritedSerializationCallback = hasInheritedImplementation ? "base.SerializationCallback_AlchemyImpl(isBeforeSerialize);" : string.Empty; var inheritedSerializationCallback = hasInheritedImplementation
? "base.SerializationCallback_AlchemyImpl(isBeforeSerialize);"
: string.Empty;
var hasShowSerializationData = typeSymbol.GetAttributes().Any(x => var hasShowSerializationData = typeSymbol.GetAttributes().Any(x => x.AttributeClass.Name
x.AttributeClass.Name is "ShowAlchemySerializationData" is "ShowAlchemySerializationData"
or "ShowAlchemySerializationDataAttribute" or "ShowAlchemySerializationDataAttribute"
or "Alchemy.Serialization.ShowAlchemySerializationData" or "Alchemy.Serialization.ShowAlchemySerializationData"
or "Alchemy.Serialization.ShowAlchemySerializationDataAttribute"); or "Alchemy.Serialization.ShowAlchemySerializationDataAttribute");
var serializationDataAttributesCode = hasShowSerializationData ? "[global::Alchemy.Inspector.ReadOnly, global::UnityEngine.TextArea(3, 999), global::UnityEngine.SerializeField]" : "[global::UnityEngine.HideInInspector, global::UnityEngine.SerializeField]"; var serializationDataAttributesCode = hasShowSerializationData
? "[global::Alchemy.Inspector.ReadOnly, global::UnityEngine.TextArea(3, 999), global::UnityEngine.SerializeField]"
: "[global::UnityEngine.HideInInspector, global::UnityEngine.SerializeField]";
// target class namespace // target class namespace
var ns = typeSymbol.ContainingNamespace.IsGlobalNamespace ? string.Empty : $"namespace {typeSymbol.ContainingNamespace} {{"; var ns = typeSymbol.ContainingNamespace.IsGlobalNamespace
? string.Empty
: $"namespace {typeSymbol.ContainingNamespace} {{";
foreach (var field in fieldSymbols) foreach (var field in fieldSymbols)
{ {
var serializeCode = var serializeCode =
@$"try @$"try
{{ {{
{alchemySerializationDataName}.{field.Name}.data = global::Alchemy.Serialization.Internal.SerializationHelper.ToJson(this.{field.Name} , {alchemySerializationDataName}.UnityObjectReferences); {alchemySerializationDataName}.{field.Name}.data = global::Alchemy.Serialization.Internal.SerializationHelper.ToJson(this.{field.Name} , {alchemySerializationDataName}.UnityObjectReferences);
{alchemySerializationDataName}.{field.Name}.isCreated = true; {alchemySerializationDataName}.{field.Name}.isCreated = true;
@ -176,8 +190,8 @@ catch (global::System.Exception ex)
global::UnityEngine.Debug.LogException(ex); global::UnityEngine.Debug.LogException(ex);
}}"; }}";
var deserializeCode = var deserializeCode =
@$"try @$"try
{{ {{
if ({alchemySerializationDataName}.{field.Name}.isCreated) if ({alchemySerializationDataName}.{field.Name}.isCreated)
{{ {{
@ -195,8 +209,8 @@ catch (global::System.Exception ex)
serializationDataCodeBuilder.Append("public Item ").Append(field.Name).Append(" = new();"); serializationDataCodeBuilder.Append("public Item ").Append(field.Name).Append(" = new();");
} }
return return
@$" @$"
// <auto-generated/> // <auto-generated/>
{ns} {ns}
@ -277,7 +291,7 @@ catch (global::System.Exception ex)
{ {
var hasAttribute = typeDeclarationSyntax.AttributeLists var hasAttribute = typeDeclarationSyntax.AttributeLists
.SelectMany(x => x.Attributes) .SelectMany(x => x.Attributes)
.Any(x => x.Name.ToString() .Any(x => x.Name.ToString()
is "AlchemySerialize" is "AlchemySerialize"
or "AlchemySerializeAttribute" or "AlchemySerializeAttribute"
or "Alchemy.Serialization.AlchemySerialize" or "Alchemy.Serialization.AlchemySerialize"