public IEnumerable <AssemblyDefinition> GetIncludedReferences()
        {
            var includedReferences = new List <AssemblyDefinition>();

            var resolver = _moduleDefinition.AssemblyResolver;

            foreach (var assemblyReference in _moduleDefinition.AssemblyReferences)
            {
                var referenceName = assemblyReference.Name;

                if (!ShouldReferenceBeIncluded(assemblyReference))
                {
                    continue;
                }

                var assembly = resolver.Resolve(referenceName);
                if (assembly != null)
                {
                    FodyEnvironment.LogInfo(string.Format("Including reference '{0}'", referenceName));

                    includedReferences.Add(assembly);
                }
            }

            if (!_configuration.ExcludeOptimizedAssemblies)
            {
                var splittedReferences = _moduleWeaver.References.Split(new [] { ";" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var splittedReference in splittedReferences)
                {
                    var assemblyDefinition = AssemblyDefinition.ReadAssembly(splittedReference);

                    var isIncluded = (from reference in includedReferences
                                      where string.Equals(reference.FullName, assemblyDefinition.FullName)
                                      select reference).Any();

                    if (!isIncluded)
                    {
                        var referenceName = assemblyDefinition.Name.Name;

                        if (!ShouldReferenceBeIncluded(assemblyDefinition.Name))
                        {
                            continue;
                        }

                        var assembly = resolver.Resolve(referenceName);
                        if (assembly != null)
                        {
                            FodyEnvironment.LogInfo(string.Format("Including reference '{0}', it was optimized away by the compiler but still adding it",
                                                                  referenceName));

                            includedReferences.Add(assembly);
                        }
                    }
                }
            }

            return(includedReferences);
        }
        public void Execute()
        {
            if (!FodyEnvironment.IsCatelMvvmAvailable)
            {
                FodyEnvironment.LogInfo("Skipping weaving of exposed properties because this is an MVVM feature");
                return;
            }

            var warningChecker = new ExposedPropertiesWarningChecker(_catelTypeNodeBuilder);

            warningChecker.Execute();

            var weaver = new ExposedPropertiesWeaver(_catelTypeNodeBuilder, _msCoreReferenceFinder);

            weaver.Execute();
        }
        private bool ShouldReferenceBeIncluded(AssemblyNameReference assemblyNameReference)
        {
            var assemblyName        = assemblyNameReference.Name;
            var assemblyNameLowered = assemblyNameReference.Name.ToLower();

            foreach (var knownIgnoredAssembly in KnownIgnoredAssemblies)
            {
                if (assemblyNameLowered.Contains(knownIgnoredAssembly.ToLower()))
                {
                    FodyEnvironment.LogInfo(string.Format("Ignoring '{0}' because it is a known assembly to be ignored", assemblyName));
                    return(false);
                }
            }

            if (_configuration.IncludeAssemblies.Any())
            {
                bool contains = _configuration.IncludeAssemblies.Any(x => string.Equals(assemblyNameLowered, x.ToLower()));

                if (!contains)
                {
                    FodyEnvironment.LogInfo(string.Format("Ignoring '{0}' because it is not in the included list", assemblyName));
                }

                return(contains);
            }

            if (_configuration.ExcludeAssemblies.Any())
            {
                var contains = _configuration.ExcludeAssemblies.Any(x => string.Equals(assemblyNameLowered, x.ToLower()));

                if (contains)
                {
                    FodyEnvironment.LogInfo(string.Format("Ignoring '{0}' because it is in the excluded list", assemblyName));
                }

                return(!contains);
            }

            return(true);
        }
        public MethodDefinition Execute()
        {
            var debugWriteLineMethod = FindDebugWriteLineMethod();

            if (debugWriteLineMethod == null)
            {
                FodyEnvironment.LogInfo("Can't find Debug.WriteLine, won't be writing debug info during assembly loading");
            }

            var loadMethod = new MethodDefinition("LoadTypesOnStartup", MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig, _moduleDefinition.ImportReference(_msCoreReferenceFinder.GetCoreTypeReference("Void")));

            var type                    = _msCoreReferenceFinder.GetCoreTypeReference("Type").Resolve();
            var typeImported            = _moduleDefinition.ImportReference(type);
            var getTypeFromHandleMethod = type.Methods.First(x => string.Equals(x.Name, "GetTypeFromHandle"));
            var getTypeFromHandle       = _moduleDefinition.ImportReference(getTypeFromHandleMethod);

            var body = loadMethod.Body;

            body.SimplifyMacros();

            var instructions = body.Instructions;

            if (instructions.Count == 0)
            {
                instructions.Add(Instruction.Create(OpCodes.Ret));
            }

            var referenceSelector = new ReferenceSelector(_moduleWeaver, _moduleDefinition, _configuration);

            // Note: we are looping reversed to easily add try/catch mechanism
            foreach (var assembly in referenceSelector.GetIncludedReferences().Reverse())
            {
                var firstType = assembly.MainModule.Types.FirstOrDefault(x => x.IsClass && x.IsPublic);
                if (firstType != null)
                {
                    FodyEnvironment.LogInfo($"Adding code to force load assembly '{assembly.Name}'");

                    if (debugWriteLineMethod != null)
                    {
                        // L_0001: ldstr "Loading assembly TestAssemblyToReference"
                        //L_0006: call void [System]System.Diagnostics.Debug::WriteLine(string)

                        // Temporarily disabled because we first need to investigate if this is ever useful
                        //instructions.Add(Instruction.Create(OpCodes.Ldstr, string.Format("Loading assembly {0}", assembly.Name)));
                        //instructions.Add(Instruction.Create(OpCodes.Call, debugWriteLineMethod));
                    }

                    // var type = typeof(FirstTypeInAssembly);
                    // ==
                    //L_000a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)

                    var firstTypeImported = _moduleDefinition.ImportReference(firstType);

                    var variable = new VariableDefinition(typeImported);
                    body.Variables.Insert(0, variable);

                    var instructionsToAdd = new[]
                    {
                        Instruction.Create(OpCodes.Ldtoken, firstTypeImported),
                        Instruction.Create(OpCodes.Call, getTypeFromHandle),
                        Instruction.Create(OpCodes.Stloc, variable)
                    };

                    instructions.Insert(0, instructionsToAdd);

                    if (_configuration.WrapInTryCatch)
                    {
                        var firstInstructionAfterInjectedSet = instructions[instructionsToAdd.Length];

                        // Pop means empty catch
                        var emptyCatchInstructions = new[]
                        {
                            Instruction.Create(OpCodes.Leave_S, firstInstructionAfterInjectedSet),
                            Instruction.Create(OpCodes.Pop),
                            Instruction.Create(OpCodes.Leave_S, firstInstructionAfterInjectedSet)
                        };

                        instructions.Insert(instructionsToAdd.Length, emptyCatchInstructions);

                        var tryStartInstruction     = instructionsToAdd.First();
                        var tryEndInstruction       = emptyCatchInstructions.Skip(1).First();
                        var handlerStartInstruction = emptyCatchInstructions.Skip(1).First();
                        var handlerEndInstruction   = firstInstructionAfterInjectedSet;

                        var handler = new ExceptionHandler(ExceptionHandlerType.Catch)
                        {
                            TryStart     = tryStartInstruction,
                            TryEnd       = tryEndInstruction,
                            HandlerStart = handlerStartInstruction,
                            HandlerEnd   = handlerEndInstruction,
                            CatchType    = _moduleDefinition.ImportReference(_msCoreReferenceFinder.GetCoreTypeReference("Exception"))
                        };

                        body.ExceptionHandlers.Insert(0, handler);
                    }
                }
            }

            instructions.Add(Instruction.Create(OpCodes.Ret));

            body.OptimizeMacros();

            //.class public abstract auto ansi sealed beforefieldinit LoadAssembliesOnStartup extends [mscorlib]System.Object
            var typeDefinition = new TypeDefinition(string.Empty, "LoadAssembliesOnStartup", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit,
                                                    _moduleDefinition.ImportReference(_msCoreReferenceFinder.GetCoreTypeReference("System.Object")));

            typeDefinition.Methods.Add(loadMethod);
            _moduleDefinition.Types.Add(typeDefinition);

            return(loadMethod);
        }
예제 #5
0
        private bool ShouldReferenceBeIncluded(AssemblyNameReference assemblyNameReference)
        {
            var assemblyName        = assemblyNameReference.Name;
            var assemblyNameLowered = assemblyNameReference.Name.ToLower();

            foreach (var knownIgnoredAssembly in KnownIgnoredPartialAssemblies)
            {
                var name = knownIgnoredAssembly.ToLower();

                if (assemblyNameLowered.Contains(name))
                {
                    FodyEnvironment.LogInfo($"Ignoring '{assemblyName}' because it is a known assembly to be ignored (via partial match '{knownIgnoredAssembly}')");
                    return(false);
                }
            }

            foreach (var knownIgnoredAssembly in KnownIgnoredExactAssemblies)
            {
                var name = knownIgnoredAssembly.ToLower();

                if (assemblyNameLowered.Equals(name))
                {
                    FodyEnvironment.LogInfo($"Ignoring '{name}' because it is a known assembly to be ignored (via exact match '{knownIgnoredAssembly}')");
                    return(false);
                }
            }

            if (_configuration.IncludeAssemblies.Any())
            {
                var contains = _configuration.IncludeAssemblies.Any(x => string.Equals(assemblyNameLowered, x.ToLower()));
                if (!contains)
                {
                    FodyEnvironment.LogInfo($"Ignoring '{assemblyName}' because it is not in the included list");
                }

                return(contains);
            }

            if (_configuration.ExcludeAssemblies.Any())
            {
                var contains = _configuration.ExcludeAssemblies.Any(x => string.Equals(assemblyNameLowered, x.ToLower()));
                if (contains)
                {
                    FodyEnvironment.LogInfo($"Ignoring '{assemblyName}' because it is in the excluded list");
                    return(false);
                }

                // Don't return here, allow it to check for private assemblies, we don't want to include *everything*
                // just because 1 or 2 are being excluded
            }

            if (_configuration.ExcludeSystemAssemblies)
            {
                foreach (var systemAssemblyPrefix in SystemAssemblyPrefixes)
                {
                    // Special case: System.dll, we don't want to include "System" to the prefixes, that would be too strict
                    if (assemblyName.IndexOf(systemAssemblyPrefix, StringComparison.OrdinalIgnoreCase) == 0 ||
                        assemblyName.Equals("System", StringComparison.OrdinalIgnoreCase))
                    {
                        FodyEnvironment.LogInfo($"Ignoring '{assemblyName}' because it is a system assembly");
                        return(false);
                    }
                }
            }

            if (_configuration.ExcludePrivateAssemblies)
            {
                if (IsPrivateReference(assemblyName))
                {
                    FodyEnvironment.LogInfo($"Ignoring '{assemblyName}' because it is a private assembly");
                    return(false);
                }
                // TODO: How to determine private assemblies, do we have access to the csproj?
                //foreach (var systemAssemblyPrefix in SystemAssemblyPrefixes)
                //{
                //    if (assemblyNameLowered.IndexOf(systemAssemblyPrefix, StringComparison.OrdinalIgnoreCase) == 0)
                //    {
                //        FodyEnvironment.LogInfo($"Ignoring '{assemblyName}' because it is a system assembly");
                //        return false;
                //    }
                //}
            }

            return(_configuration.OptOut);
        }