static TypeManager() { string assemblyLocation; var isBundled = BundleHelper.InitializeBundledAssemblies(); Instance = new TypeManager(isBundled); if (isBundled) { foreach (var name in BundleHelper.GetBundledAssembliesNames()) { Instance.ScanFile(name, bundled: true); } // in case of a bundled version `Assembly.GetExecutingAssembly().Location` returns an empty string assemblyLocation = Directory.GetCurrentDirectory(); } else { assemblyLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } Instance.Scan(assemblyLocation); }
private TypeDefinition ResolveInner(TypeReference tp) { if (isBundled) { try { var scope = tp.GetElementType().Scope.ToString(); var bundled = BundleHelper.GetBundledAssemblyByFullName(scope); if (bundled != null) { if (tp.IsArray) { // this supports only one-dimensional arrays for now var elementType = bundled.MainModule.GetType(tp.Namespace, tp.GetElementType().Name); return(new ArrayType(elementType).Resolve()); } return(bundled.MainModule.GetType(tp.Namespace, tp.Name)); } } catch { // intentionally do nothing, we'll try to resolve it later } } try { return(tp.Resolve()); } catch { // we couldn't resolve it in any way, just give up return(null); } }
private bool AnalyzeAssembly(string path, bool abortOnDuplicatedAssembly = false, bool bundled = false) { 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) ? BundleHelper.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) { // 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, "File {0} could not be analyzed due to invalid format.", path); 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); } foreach (var type in module.GetTypes()) { types.Add(type); } } 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 (!ExtractExtensionMethods(type) && !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)) { if (abortOnDuplicatedAssembly) { Logger.LogAs(this, LogLevel.Warning, "Trying to load assembly that has been already loaded."); return(false); } var description = assemblyFromTypeName[fullName]; assemblyFromTypeName.Remove(fullName); assembliesFromTypeName.Add(fullName, new List <AssemblyDescription> { description, newAssemblyDescription }); continue; } assemblyFromTypeName.Add(fullName, newAssemblyDescription); } return(true); }