コード例 #1
0
        private bool AnalyzeAssembly(string path, bool bundled = false, bool throwOnBadImage = true)
        {
            Logger.LogAs(this, LogLevel.Noisy, "Analyzing assembly {0}.", path);
            if (assemblyFromAssemblyName.Values.Any(x => x.Path == path))
            {
                Logger.LogAs(this, LogLevel.Warning, "Assembly {0} was already analyzed.", path);
                return(true);
            }
            AssemblyDefinition assembly;

            try
            {
                assembly = (bundled)
                    ? AssemblyHelper.GetBundledAssemblyByName(path)
                    : AssemblyDefinition.ReadAssembly(path);
            }
            catch (DirectoryNotFoundException)
            {
                Logger.LogAs(this, LogLevel.Warning, "Could not find file {0} to analyze.", path);
                return(false);
            }
            catch (FileNotFoundException)
            {
                Logger.LogAs(this, LogLevel.Warning, "Could not find file {0} to analyze.", path);
                return(false);
            }
            catch (BadImageFormatException)
            {
                var message = string.Format("File {0} could not be analyzed due to invalid format.", path);
                if (throwOnBadImage)
                {
                    throw new RecoverableException(message);
                }
                // we hush this log because it is issued in binary Windows packages - we look for DLL files, but we
                // also bundle libgcc etc.
                Logger.LogAs(this, LogLevel.Noisy, message);
                return(false);
            }
            var assemblyName = assembly.FullName;

            if (!assemblyFromAssemblyName.ContainsKey(assemblyName))
            {
                assemblyFromAssemblyName.Add(assemblyName, GetAssemblyDescription(assemblyName, path));
            }
            else
            {
                if (path == assemblyFromAssemblyName[assemblyName].Path)
                {
                    return(true);
                }
                var description = assemblyFromAssemblyName[assemblyName];
                Logger.LogAs(this, LogLevel.Warning, "Assembly {0} is hidden by one located in {1} (same simple name {2}).",
                             path, description.Path, assemblyName);
            }
            var types = new List <TypeDefinition>();

            foreach (var module in assembly.Modules)
            {
                // we add the assembly's directory to the resolve directory - also all known directories
                knownDirectories.Add(Path.GetDirectoryName(path));
                var defaultAssemblyResolver = ((DefaultAssemblyResolver)module.AssemblyResolver);
                foreach (var directory in knownDirectories)
                {
                    defaultAssemblyResolver.AddSearchDirectory(directory);
                }
                types.AddRange(module.GetTypes());
            }

            var hidePluginsFromThisAssembly = false;

            // It happens that `entryAssembly` is null, e.g., when running tests inside MD.
            // In such case we don't care about hiding plugins, so we just skip this mechanism (as this is the simples solution to the NRE problem).
            var entryAssembly = Assembly.GetEntryAssembly();

            if (entryAssembly != null && IsReferenced(entryAssembly, assembly.FullName))
            {
                Logger.LogAs(this, LogLevel.Noisy, "Plugins from this assembly {0} will be hidden as it is explicitly referenced.", assembly.FullName);
                hidePluginsFromThisAssembly = true;
            }

            foreach (var type in types)
            {
                if (type.Interfaces.Any(i => ResolveInner(i)?.GetFullNameOfMember() == typeof(IPeripheral).FullName))
                {
                    Logger.LogAs(this, LogLevel.Noisy, "Peripheral type {0} found.", type.Resolve().GetFullNameOfMember());
                    foundPeripherals.Add(type);
                }

                if (type.CustomAttributes.Any(x => ResolveInner(x.AttributeType)?.GetFullNameOfMember() == typeof(PluginAttribute).FullName))
                {
                    Logger.LogAs(this, LogLevel.Noisy, "Plugin type {0} found.", type.Resolve().GetFullNameOfMember());
                    try
                    {
                        foundPlugins.Add(new PluginDescriptor(type, hidePluginsFromThisAssembly));
                    }
                    catch (Exception e)
                    {
                        //This may happend due to, e.g., version parsing error. The plugin is ignored.
                        Logger.LogAs(this, LogLevel.Error, "Plugin type {0} loading error: {1}.", type.GetFullNameOfMember(), e.Message);
                    }
                }

                if (IsAutoLoadType(type))
                {
                    var loadedType = GetTypeWithLazyLoad(type.GetFullNameOfMember(), assembly.FullName, path);
                    lock (autoLoadedTypeLocker)
                    {
                        autoLoadedTypes.Add(loadedType);
                    }
                    var autoLoadedType = autoLoadedTypeEvent;
                    if (autoLoadedType != null)
                    {
                        autoLoadedType(loadedType);
                    }
                    continue;
                }
                if (!TryExtractExtensionMethods(type, out var extractedMethods) && !IsInterestingType(type))
                {
                    continue;
                }
                // type is interesting, we'll put it into our dictionaries
                // after conflicts checking
                var fullName = type.GetFullNameOfMember();
                var newAssemblyDescription = GetAssemblyDescription(assembly.FullName, path);
                Logger.LogAs(this, LogLevel.Noisy, "Type {0} added.", fullName);
                if (assembliesFromTypeName.ContainsKey(fullName))
                {
                    assembliesFromTypeName[fullName].Add(newAssemblyDescription);
                    continue;
                }
                if (assemblyFromTypeName.ContainsKey(fullName))
                {
                    throw new InvalidOperationException("Tried to load assembly that has been already loaded. Aborting operation.");
                }
                assemblyFromTypeName.Add(fullName, newAssemblyDescription);
                if (extractedMethods != null)
                {
                    ProcessExtractedExtensionMethods(extractedMethods);
                }
            }

            return(true);
        }