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); }