diff --git a/Mono.Cecil/Import.cs b/Mono.Cecil/Import.cs index 272e96076..8e7c26141 100644 --- a/Mono.Cecil/Import.cs +++ b/Mono.Cecil/Import.cs @@ -14,6 +14,7 @@ using SR = System.Reflection; using Mono.Cecil.Metadata; +using System.Reflection; namespace Mono.Cecil { @@ -191,7 +192,11 @@ TypeReference ImportType (Type type, ImportGenericContext context, ImportGeneric protected virtual IMetadataScope ImportScope (Type type) { - return ImportScope (type.Assembly); + if (type.Assembly == typeof (object).Assembly && Mixin.TryGetAssemblyNameReference(module, type.Assembly.GetName(), out var scope, true)) { + return scope; + } else { + return ImportScope (type.Assembly); + } } static bool ImportOpenGenericType (Type type, ImportGenericKind import_kind) @@ -754,20 +759,69 @@ public static void CheckModule (ModuleDefinition module) throw new ArgumentNullException (Argument.module.ToString ()); } - public static bool TryGetAssemblyNameReference (this ModuleDefinition module, AssemblyNameReference name_reference, out AssemblyNameReference assembly_reference) + public static bool TryGetAssemblyNameReference (this ModuleDefinition module, AssemblyNameWrapper name_reference, out AssemblyNameReference assembly_reference, bool check_name_only = false) { - var references = module.AssemblyReferences; - - for (int i = 0; i < references.Count; i++) { - var reference = references [i]; - if (!Equals (name_reference, reference)) - continue; + // Try to resolve the assembly using direct reference first + if (module.TryGetDirectAssemblyNameReference (name_reference, out assembly_reference)) { + return true; + } - assembly_reference = reference; + // If direct resolution fails, try to resolve using forwarded types + if (module.TryGetForwardedAssemblyNameReference (name_reference, out assembly_reference, check_name_only)) { return true; } + // If resolution fails, set the output reference to null + assembly_reference = null; + return false; + } + + static bool TryGetDirectAssemblyNameReference (this ModuleDefinition module, AssemblyNameWrapper name_reference, out AssemblyNameReference assembly_reference) + { + // Check each assembly reference in the module for a match by full name + foreach (var reference in module.AssemblyReferences) { + if (reference.FullName == name_reference.FullName) { + assembly_reference = reference; + return true; + } + } + + // If no direct reference is found, set the output reference to null + assembly_reference = null; + return false; + } + + static bool TryGetForwardedAssemblyNameReference (this ModuleDefinition module, AssemblyNameWrapper name_reference, out AssemblyNameReference assembly_reference, bool check_name_only) + { + // Initialize the output parameter to null assembly_reference = null; + + // Iterate through all assembly references + foreach (var asm_ref in module.AssemblyReferences) { + AssemblyDefinition resolved_assembly; + try { + // Attempt to resolve the assembly reference + resolved_assembly = module.AssemblyResolver.Resolve (asm_ref); + } + catch (AssemblyResolutionException) { + // Skip the assembly if resolution fails + continue; + } + + // Check exported types for type forwarding within the assembly + foreach (ModuleDefinition module_def in resolved_assembly.Modules) { + foreach (ExportedType exported_type in module_def.ExportedTypes) { + // Check if the exported type has a scope that matches the target assembly name + var scope = exported_type.Scope as AssemblyNameReference; + if (scope != null && AssemblyNameWrapper.Equals (scope, name_reference, check_name_only)) { + // If a match is found, return the assembly reference from which the type was forwarded + assembly_reference = asm_ref; + return true; + } + } + } + } + return false; } @@ -794,19 +848,104 @@ static bool Equals (T a, T b) where T : class, IEquatable return a.Equals (b); } - static bool Equals (AssemblyNameReference a, AssemblyNameReference b) - { - if (ReferenceEquals (a, b)) + public sealed class AssemblyNameWrapper { + private readonly AssemblyName assembly_name; + private readonly AssemblyNameReference assembly_name_reference; + + public AssemblyNameWrapper (AssemblyName assembly_name) + { + CheckName (assembly_name); + this.assembly_name = assembly_name; + } + + public AssemblyNameWrapper (AssemblyNameReference assembly_name_reference) + { + CheckName (assembly_name_reference); + this.assembly_name_reference = assembly_name_reference; + } + + public string FullName { + get { + if (assembly_name == null) { + return assembly_name_reference.FullName; + } else { + return assembly_name.FullName; + } + } + } + + public string Name { + get { + if (assembly_name == null) { + return assembly_name_reference.Name; + } else { + return assembly_name.Name; + } + } + } + + public Version Version { + get { + if (assembly_name == null) { + return assembly_name_reference.Version; + } else { + return assembly_name.Version; + } + } + } + + public byte [] PublicKeyToken { + get { + if (assembly_name == null) { + return assembly_name_reference.PublicKeyToken; + } else { + return assembly_name.GetPublicKeyToken(); + } + } + } + + public string Culture { + get { + if (assembly_name == null) { + return assembly_name_reference.Culture; + } else { + return assembly_name.CultureInfo.Name; + } + } + } + + public static bool Equals (AssemblyNameWrapper a, AssemblyNameWrapper b, bool check_name_only) + { + if (ReferenceEquals (a, b)) + return true; + if(a.assembly_name != null && ReferenceEquals(a.assembly_name, b.assembly_name)) + return true; + if (a.assembly_name_reference != null && ReferenceEquals (a.assembly_name_reference, b.assembly_name_reference)) + return true; + if (a.Name != b.Name) + return false; + + if (!check_name_only) { + if (!Equals (a.Version, b.Version)) + return false; + if (a.Culture != b.Culture) + return false; + if (!Equals (a.PublicKeyToken, b.PublicKeyToken)) + return false; + } + return true; - if (a.Name != b.Name) - return false; - if (!Equals (a.Version, b.Version)) - return false; - if (a.Culture != b.Culture) - return false; - if (!Equals (a.PublicKeyToken, b.PublicKeyToken)) - return false; - return true; + } + + public static implicit operator AssemblyNameWrapper (AssemblyName assembly_name) + { + return new AssemblyNameWrapper (assembly_name); + } + + public static implicit operator AssemblyNameWrapper (AssemblyNameReference assembly_name_reference) + { + return new AssemblyNameWrapper (assembly_name_reference); + } } } }