Skip to content

Commit

Permalink
Enhance assembly name reference resolution in ModuleDefinition
Browse files Browse the repository at this point in the history
- Improve TryGetAssemblyNameReference to handle direct and forwarded assembly references.
- Implement helper methods for resolving direct and forwarded assembly references.
  • Loading branch information
Denis Kudelin committed Nov 14, 2023
1 parent 56d4409 commit 89cb8cf
Showing 1 changed file with 160 additions and 21 deletions.
181 changes: 160 additions & 21 deletions Mono.Cecil/Import.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using SR = System.Reflection;

using Mono.Cecil.Metadata;
using System.Reflection;

namespace Mono.Cecil {

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}

Expand All @@ -794,19 +848,104 @@ static bool Equals<T> (T a, T b) where T : class, IEquatable<T>
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);
}
}
}
}

0 comments on commit 89cb8cf

Please sign in to comment.