diff --git a/Assets/Sample/Test.unity b/Assets/Sample/Test.unity index 23d792e..1ce0c90 100644 --- a/Assets/Sample/Test.unity +++ b/Assets/Sample/Test.unity @@ -257,6 +257,6 @@ MonoBehaviour: references: version: 1 00000000: - type: {class: ILibInterface`1/LibGenericObject, ns: , asm: Assembly-CSharp} + type: {class: ILibInterface`1/LibIntObject, ns: , asm: Assembly-CSharp} 00000001: type: {class: ILibInterface`1/LibGenericObject_2, ns: , asm: Assembly-CSharp} diff --git a/Assets/Sample/TestSO.cs b/Assets/Sample/TestSO.cs index 30fdeac..a4e3a4d 100644 --- a/Assets/Sample/TestSO.cs +++ b/Assets/Sample/TestSO.cs @@ -5,7 +5,7 @@ namespace GenericSerializeReference.Sample [CreateAssetMenu(fileName = "TestSO", menuName = "TestSO", order = 0)] public class TestSO : ScriptableObject { - [GenericSerializeReference] + [GenericSerializeReference(mode: GenerateMode.Embed)] public MultipleGeneric.IInterface IntFloat { get; set; } } } \ No newline at end of file diff --git a/Assets/__.cs b/Assets/__.cs index 0334868..43ec444 100644 --- a/Assets/__.cs +++ b/Assets/__.cs @@ -1,4 +1,5 @@ -namespace GenericSerializeReference.Library.CodeGen +namespace GenericSerializeReference { - internal static class ___ {} + // just make sure there has `AssemblyCSharp.dll` + static class ___ {} } diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs index e5fad54..c2d5db0 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs @@ -28,104 +28,106 @@ public override bool WillProcess(ICompiledAssembly compiledAssembly) public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) { - var logger = new ILPostProcessorLogger(new List()); using var resolver = new PostProcessorAssemblyResolver(compiledAssembly.References); using var assembly = compiledAssembly.LoadAssembly(resolver); - var referenceAssemblies = compiledAssembly.LoadLibraryAssemblies(resolver).ToArray(); - try + var logger = assembly.CreateLogger(); + logger.Info($"process GenericSerializeReference on {assembly.Name.Name}({string.Join(",", compiledAssembly.References.Where(r => r.StartsWith("Library")))})"); + var modified = Process(compiledAssembly, assembly, resolver, logger); + if (!modified) return new ILPostProcessResult(null, logger.Messages); + + var pe = new MemoryStream(); + var pdb = new MemoryStream(); + var writerParameters = new WriterParameters { - var loggerAttributes = assembly.GetAttributesOf(); - if (loggerAttributes.Any()) logger.LogLevel = (LogLevel)loggerAttributes.First().ConstructorArguments[0].Value; - logger.Info($"process GenericSerializeReference on {assembly.Name.Name}({string.Join(",", referenceAssemblies.Select(r => r.Name.Name))})"); - var allTypes = referenceAssemblies.Append(assembly) - .Where(asm => !asm.Name.Name.StartsWith("Unity.") - && !asm.Name.Name.StartsWith("UnityEditor.") - && !asm.Name.Name.StartsWith("UnityEngine.") - ) - .SelectMany(asm => asm.MainModule.GetAllTypes()) - ; - logger.Debug($"all types: {string.Join(", ", allTypes.Select(t => t.Name))}"); - var typeTree = new TypeTree(allTypes); - logger.Debug($"tree: {typeTree}"); - var modified = Process(assembly.MainModule, typeTree, logger); - if (!modified) return new ILPostProcessResult(null, logger.Messages); + SymbolWriterProvider = new PortablePdbWriterProvider(), SymbolStream = pdb, WriteSymbols = true + }; + assembly.Write(pe, writerParameters); + // assembly.Write(); + var inMemoryAssembly = new InMemoryAssembly(pe.ToArray(), pdb.ToArray()); + return new ILPostProcessResult(inMemoryAssembly, logger.Messages); + } - var pe = new MemoryStream(); - var pdb = new MemoryStream(); - var writerParameters = new WriterParameters - { - SymbolWriterProvider = new PortablePdbWriterProvider(), SymbolStream = pdb, WriteSymbols = true - }; - assembly.Write(pe, writerParameters); - // assembly.Write(); - var inMemoryAssembly = new InMemoryAssembly(pe.ToArray(), pdb.ToArray()); - return new ILPostProcessResult(inMemoryAssembly, logger.Messages); + private bool Process(ICompiledAssembly compiledAssembly, AssemblyDefinition assembly, PostProcessorAssemblyResolver resolver, ILPostProcessorLogger logger) + { + var module = assembly.MainModule; + IReadOnlyList referenceAssemblies = Array.Empty(); + TypeTree typeTree = null; + + try + { + return ProcessProperties(); } finally { - foreach (var reference in referenceAssemblies) reference.Dispose(); + foreach (var @ref in referenceAssemblies) @ref.Dispose(); } - } - private bool Process(ModuleDefinition module, TypeTree typeTree, ILPostProcessorLogger logger) - { - var modified = false; - foreach (var (type, property, attribute) in - from type in module.GetAllTypes() - where type.IsClass && !type.IsAbstract - from property in type.Properties.ToArray() // able to change `Properties` during looping - from attribute in property.GetAttributesOf() - select (type, property, attribute) - ) + bool ProcessProperties() { - if (property.GetMethod == null) + var modified = false; + foreach (var (type, property, attribute) in + from type in module.GetAllTypes() + where type.IsClass && !type.IsAbstract + from property in type.Properties.ToArray() // able to change `Properties` during looping + from attribute in property.GetAttributesOf() + select (type, property, attribute) + ) { - logger.Warning($"Cannot process on property {property} without getter"); - continue; - } + if (property.GetMethod == null) + { + logger.Warning($"Cannot process on property {property} without getter"); + continue; + } - if (!property.PropertyType.IsGenericInstance) - { - logger.Warning($"Cannot process on property {property} with non-generic type {property.PropertyType.Name}"); - continue; - } + if (!property.PropertyType.IsGenericInstance) + { + logger.Warning($"Cannot process on property {property} with non-generic type {property.PropertyType.Name}"); + continue; + } - TypeReference baseInterface; - var mode = (GenerateMode)attribute.ConstructorArguments[1].Value; - if (mode == GenerateMode.Embed) - { - var wrapperName = $"<{property.Name}>__generic_serialize_reference"; - var wrapper = property.DeclaringType.CreateNestedStaticPrivateClass(wrapperName); - baseInterface = CreateInterface(wrapper); - CreateDerivedClasses(property, wrapper, baseInterface); - } - else - { - baseInterface = module.ImportReference(typeof(IBase)); - } + TypeReference baseInterface; + var mode = (GenerateMode)attribute.ConstructorArguments[1].Value; + if (mode == GenerateMode.Embed) + { + var wrapperName = $"<{property.Name}>__generic_serialize_reference"; + var wrapper = property.DeclaringType.CreateNestedStaticPrivateClass(wrapperName); + baseInterface = CreateInterface(wrapper); + CreateDerivedClasses(property, wrapper, baseInterface); + } + else + { + baseInterface = module.ImportReference(typeof(IBase)); + } - logger.Info($"generate nested class with interface {baseInterface.FullName}"); - var fieldNamePrefix = (string)attribute.ConstructorArguments[0].Value; - GenerateField(module, property, baseInterface, fieldNamePrefix); + logger.Info($"generate nested class with interface {baseInterface.FullName}"); + var fieldNamePrefix = (string)attribute.ConstructorArguments[0].Value; + GenerateField(module, property, baseInterface, fieldNamePrefix); - modified = true; + modified = true; + } + return modified; } - return modified; - TypeDefinition CreateInterface(TypeDefinition wrapper, string interfaceName = "IBase") + void CreateTypeTree() { - // .class interface nested public abstract auto ansi - var interfaceAttributes = TypeAttributes.Class | - TypeAttributes.Interface | - TypeAttributes.NestedPublic | - TypeAttributes.Abstract; - var baseInterface = new TypeDefinition("", interfaceName, interfaceAttributes); - wrapper.NestedTypes.Add(baseInterface); - return baseInterface; + if (typeTree != null) return; + + referenceAssemblies = compiledAssembly.LoadLibraryAssemblies(resolver).ToArray(); + var allTypes = referenceAssemblies.Append(assembly) + .Where(asm => !asm.Name.Name.StartsWith("Unity.") + && !asm.Name.Name.StartsWith("UnityEditor.") + && !asm.Name.Name.StartsWith("UnityEngine.") + ) + .SelectMany(asm => asm.MainModule.GetAllTypes()) + ; + logger.Debug($"all types: {string.Join(", ", allTypes.Select(t => t.Name))}"); + typeTree = new TypeTree(allTypes); + logger.Debug($"tree: {typeTree}"); } void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, TypeReference baseInterface) { + if (typeTree == null) CreateTypeTree(); logger.Debug($"get derived {property.PropertyType.Module} {property.PropertyType} {property.PropertyType.Resolve()}"); foreach (var derived in typeTree.GetOrCreateAllDerivedReference(property.PropertyType)) { @@ -151,7 +153,19 @@ void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, T } } - internal static void GenerateField( + private TypeDefinition CreateInterface(TypeDefinition wrapper, string interfaceName = "IBase") + { + // .class interface nested public abstract auto ansi + var interfaceAttributes = TypeAttributes.Class | + TypeAttributes.Interface | + TypeAttributes.NestedPublic | + TypeAttributes.Abstract; + var baseInterface = new TypeDefinition("", interfaceName, interfaceAttributes); + wrapper.NestedTypes.Add(baseInterface); + return baseInterface; + } + + private static void GenerateField( ModuleDefinition module, PropertyDefinition property, TypeReference fieldType, @@ -162,7 +176,7 @@ internal static void GenerateField( InjectSetter(property, serializedField); } - internal static FieldDefinition CreateSerializeReferenceField( + private static FieldDefinition CreateSerializeReferenceField( ModuleDefinition module, PropertyDefinition property, TypeReference @interface, @@ -183,7 +197,7 @@ internal static FieldDefinition CreateSerializeReferenceField( return serializedField; } - internal static void InjectGetter(PropertyDefinition property, FieldDefinition serializedField) + private static void InjectGetter(PropertyDefinition property, FieldDefinition serializedField) { // --------add-------- // IL_0000: ldarg.0 // this @@ -206,7 +220,7 @@ internal static void InjectGetter(PropertyDefinition property, FieldDefinition s instructions.Insert(4, Instruction.Create(OpCodes.Pop)); } - internal static void InjectSetter(PropertyDefinition property, FieldDefinition serializedField) + private static void InjectSetter(PropertyDefinition property, FieldDefinition serializedField) { //IL_0000: ldarg.0 // this //IL_0001: ldarg.1 // 'value' diff --git a/Packages/generic-serialize-reference/package.json b/Packages/generic-serialize-reference/package.json index 1829e1c..a0cc9f4 100644 --- a/Packages/generic-serialize-reference/package.json +++ b/Packages/generic-serialize-reference/package.json @@ -1,7 +1,7 @@ { "name": "com.quabug.generic-serialize-reference", "description": "Automatically alter generic field of SerializeReference into its non-generic form", - "version": "1.2.0", + "version": "1.2.1", "unity": "2020.2", "displayName": "GenericSerializeReference", "samples": [