Beispiel #1
0
        public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
        {
            var logger = new ILPostProcessorLogger(new List <DiagnosticMessage>());

            logger.Debug($"process {compiledAssembly.Name}({string.Join("|", compiledAssembly.References.Select(Path.GetFileName).Where(f => !new [] {"System", "Mono", "mscorlib", "netstandard", "Microsoft", "Unity", "UnityEngine"}.Any(f.StartsWith)))})");

            using var resolver           = new PostProcessorAssemblyResolver(compiledAssembly.References);
            using var assemblyDefinition = compiledAssembly.LoadAssembly(resolver);

            var modified = false;

            var nodes = assemblyDefinition.MainModule.GetAllTypes()
                        .Where(type => type.IsClass && !type.IsAbstract && type.TypeImplements(typeof(INodeData)))
                        .ToArray()
            ;

            var methods = nodes.SelectMany(FetchNodeDataMethods)
                          .Where(method => method != null && !method.CustomAttributes.FindAccessorAttributes().Any())
            ;

            foreach (var method in methods)
            {
                var attributes = method.GenerateAccessorAttributes();
                if (!attributes.Any())
                {
                    continue;
                }

                modified = true;
                method.CustomAttributes.AddRange(attributes);
            }

            return(modified ? assemblyDefinition.Write(logger.Messages) : new ILPostProcessResult(null, logger.Messages));
        }
Beispiel #2
0
        private static AssemblyDefinition LoadAssemblyDefinition(ICompiledAssembly compiledAssembly)
        {
            var resolver         = new PostProcessorAssemblyResolver(compiledAssembly.References);
            var symbolStream     = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData.ToArray());
            var readerParameters = new ReaderParameters
            {
                SymbolStream               = symbolStream,
                SymbolReaderProvider       = new PortablePdbReaderProvider(),
                AssemblyResolver           = resolver,
                ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(),
                ReadingMode = ReadingMode.Immediate,
            };
            var peStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PeData.ToArray());

            return(AssemblyDefinition.ReadAssembly(peStream, readerParameters));
        }
Beispiel #3
0
        public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
        {
            var sw = Stopwatch.StartNew();

            using var resolver = new PostProcessorAssemblyResolver(compiledAssembly.References);
            using var assembly = compiledAssembly.LoadAssembly(resolver);
            var referenceAssemblies = compiledAssembly.LoadLibraryAssemblies(resolver).ToArray();
            var logger = assembly.CreateLogger();
            var module = assembly.MainModule;

            try
            {
                var isVariantsGenerated = GenerateVariants();
                return(isVariantsGenerated
                    ? assembly.Write(logger.Messages)
                    : new ILPostProcessResult(null, logger.Messages));
            }
            finally
            {
                foreach (var reference in referenceAssemblies)
                {
                    reference.Dispose();
                }
                logger.Info($"process Variants ({sw.ElapsedMilliseconds}ms) on {assembly.Name.Name}({string.Join(",", compiledAssembly.References.Where(r => r.StartsWith("Library")))})");
            }

            bool GenerateVariants()
            {
                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())
                               .Where(type => type.GetAttributesOf <VariantClassAttribute>().Any())
                               .SelectMany(type => type.NestedTypes)
                               .ToArray()
                ;
                var typeTree   = new TypeTree(allTypes, logger);
                var valueTypes = referenceAssemblies.Append(assembly)
                                 .SelectMany(asm => asm.GetAttributesOf <VariantValueTypeAttribute>())
                                 .Select(attribute => (TypeReference)attribute.ConstructorArguments[0].Value)
                                 .Select(valueType => module.ImportReference(valueType.Resolve()))
                                 .ToArray()
                ;

                var wrappers = new[] { typeof(IVariantReader <>), typeof(IVariantWriter <>), typeof(IVariantReaderAndWriter <>) }
                // .AsParallel()
                .Select(GenerateVariantsWrapper)
                .Where(wrapper => wrapper != null)
                .ToArray()
                ;

                module.Types.AddRange(wrappers);
                return(wrappers.Any());

                TypeDefinition GenerateVariantsWrapper(Type interfaceType)
                {
                    var @interface = module.ImportReference(interfaceType);

                    if (!typeTree.HasBaseType(@interface.Resolve()))
                    {
                        return(null);
                    }

                    logger.Info($"process interface {@interface.Name} @ {Thread.CurrentThread.ManagedThreadId}");

                    var wrapper = new TypeDefinition(
                        "EntitiesBT.Variant.CodeGen",
                        $"<{@interface.Name.Split('`')[0]}>",
                        TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.Public | TypeAttributes.BeforeFieldInit
                        );

                    wrapper.BaseType = module.ImportReference(typeof(object));

                    foreach (var(valueType, variantType) in
                             from valueType in valueTypes
                             from variantType in typeTree.GetOrCreateAllDerivedReference(@interface.MakeGenericInstanceType(valueType))
                             select(valueType, module.ImportReference(variantType))
                             )
                    {
                        var className         = $"{valueType.Name}{variantType.DeclaringType.Name}";
                        var variantDefinition = CreateVariantDefinition(variantType, className);
                        if (variantDefinition != null)
                        {
                            wrapper.NestedTypes.Add(variantDefinition);
                        }
                    }

                    return(wrapper.NestedTypes.Any() ? wrapper : null);
                }

                TypeDefinition CreateVariantDefinition(TypeReference variantType, string className)
                {
                    var genericArguments = variantType.IsGenericInstance
                            ? ((GenericInstanceType)variantType).GenericArguments
                            : (IEnumerable <TypeReference>)Array.Empty <TypeReference>()
                    ;

                    if (genericArguments.All(arg => !arg.IsGenericParameter))
                    {
                        var classAttributes = TypeAttributes.Class | TypeAttributes.NestedPublic |
                                              TypeAttributes.BeforeFieldInit;
                        var generated = new TypeDefinition("", className, classAttributes);
                        generated.BaseType = variantType.HasGenericParameters
                            ? variantType.MakeGenericInstanceType(genericArguments.ToArray())
                            : variantType;
                        var ctor = module
                                   .ImportReference(variantType.Resolve().GetConstructors().First(c => !c.HasParameters))
                                   .Resolve();
                        var ctorCall = new MethodReference(ctor.Name, module.ImportReference(ctor.ReturnType))
                        {
                            DeclaringType     = generated.BaseType,
                            HasThis           = ctor.HasThis,
                            ExplicitThis      = ctor.ExplicitThis,
                            CallingConvention = ctor.CallingConvention,
                        };
                        generated.AddEmptyCtor(ctorCall);
                        return(generated);
                    }

                    return(null);
                }
            }
        }
Beispiel #4
0
 public static IEnumerable <AssemblyDefinition> LoadLibraryAssemblies(this ICompiledAssembly compiledAssembly, PostProcessorAssemblyResolver resolver)
 {
     return(compiledAssembly.References.Where(name => name.StartsWith("Library")).Select(resolver.Resolve));
 }