Skip to content

Commit 89cb8cf

Browse files
author
Denis Kudelin
committed
Enhance assembly name reference resolution in ModuleDefinition
- Improve TryGetAssemblyNameReference to handle direct and forwarded assembly references. - Implement helper methods for resolving direct and forwarded assembly references.
1 parent 56d4409 commit 89cb8cf

File tree

1 file changed

+160
-21
lines changed

1 file changed

+160
-21
lines changed

Mono.Cecil/Import.cs

+160-21
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using SR = System.Reflection;
1515

1616
using Mono.Cecil.Metadata;
17+
using System.Reflection;
1718

1819
namespace Mono.Cecil {
1920

@@ -191,7 +192,11 @@ TypeReference ImportType (Type type, ImportGenericContext context, ImportGeneric
191192

192193
protected virtual IMetadataScope ImportScope (Type type)
193194
{
194-
return ImportScope (type.Assembly);
195+
if (type.Assembly == typeof (object).Assembly && Mixin.TryGetAssemblyNameReference(module, type.Assembly.GetName(), out var scope, true)) {
196+
return scope;
197+
} else {
198+
return ImportScope (type.Assembly);
199+
}
195200
}
196201

197202
static bool ImportOpenGenericType (Type type, ImportGenericKind import_kind)
@@ -754,20 +759,69 @@ public static void CheckModule (ModuleDefinition module)
754759
throw new ArgumentNullException (Argument.module.ToString ());
755760
}
756761

757-
public static bool TryGetAssemblyNameReference (this ModuleDefinition module, AssemblyNameReference name_reference, out AssemblyNameReference assembly_reference)
762+
public static bool TryGetAssemblyNameReference (this ModuleDefinition module, AssemblyNameWrapper name_reference, out AssemblyNameReference assembly_reference, bool check_name_only = false)
758763
{
759-
var references = module.AssemblyReferences;
760-
761-
for (int i = 0; i < references.Count; i++) {
762-
var reference = references [i];
763-
if (!Equals (name_reference, reference))
764-
continue;
764+
// Try to resolve the assembly using direct reference first
765+
if (module.TryGetDirectAssemblyNameReference (name_reference, out assembly_reference)) {
766+
return true;
767+
}
765768

766-
assembly_reference = reference;
769+
// If direct resolution fails, try to resolve using forwarded types
770+
if (module.TryGetForwardedAssemblyNameReference (name_reference, out assembly_reference, check_name_only)) {
767771
return true;
768772
}
769773

774+
// If resolution fails, set the output reference to null
775+
assembly_reference = null;
776+
return false;
777+
}
778+
779+
static bool TryGetDirectAssemblyNameReference (this ModuleDefinition module, AssemblyNameWrapper name_reference, out AssemblyNameReference assembly_reference)
780+
{
781+
// Check each assembly reference in the module for a match by full name
782+
foreach (var reference in module.AssemblyReferences) {
783+
if (reference.FullName == name_reference.FullName) {
784+
assembly_reference = reference;
785+
return true;
786+
}
787+
}
788+
789+
// If no direct reference is found, set the output reference to null
790+
assembly_reference = null;
791+
return false;
792+
}
793+
794+
static bool TryGetForwardedAssemblyNameReference (this ModuleDefinition module, AssemblyNameWrapper name_reference, out AssemblyNameReference assembly_reference, bool check_name_only)
795+
{
796+
// Initialize the output parameter to null
770797
assembly_reference = null;
798+
799+
// Iterate through all assembly references
800+
foreach (var asm_ref in module.AssemblyReferences) {
801+
AssemblyDefinition resolved_assembly;
802+
try {
803+
// Attempt to resolve the assembly reference
804+
resolved_assembly = module.AssemblyResolver.Resolve (asm_ref);
805+
}
806+
catch (AssemblyResolutionException) {
807+
// Skip the assembly if resolution fails
808+
continue;
809+
}
810+
811+
// Check exported types for type forwarding within the assembly
812+
foreach (ModuleDefinition module_def in resolved_assembly.Modules) {
813+
foreach (ExportedType exported_type in module_def.ExportedTypes) {
814+
// Check if the exported type has a scope that matches the target assembly name
815+
var scope = exported_type.Scope as AssemblyNameReference;
816+
if (scope != null && AssemblyNameWrapper.Equals (scope, name_reference, check_name_only)) {
817+
// If a match is found, return the assembly reference from which the type was forwarded
818+
assembly_reference = asm_ref;
819+
return true;
820+
}
821+
}
822+
}
823+
}
824+
771825
return false;
772826
}
773827

@@ -794,19 +848,104 @@ static bool Equals<T> (T a, T b) where T : class, IEquatable<T>
794848
return a.Equals (b);
795849
}
796850

797-
static bool Equals (AssemblyNameReference a, AssemblyNameReference b)
798-
{
799-
if (ReferenceEquals (a, b))
851+
public sealed class AssemblyNameWrapper {
852+
private readonly AssemblyName assembly_name;
853+
private readonly AssemblyNameReference assembly_name_reference;
854+
855+
public AssemblyNameWrapper (AssemblyName assembly_name)
856+
{
857+
CheckName (assembly_name);
858+
this.assembly_name = assembly_name;
859+
}
860+
861+
public AssemblyNameWrapper (AssemblyNameReference assembly_name_reference)
862+
{
863+
CheckName (assembly_name_reference);
864+
this.assembly_name_reference = assembly_name_reference;
865+
}
866+
867+
public string FullName {
868+
get {
869+
if (assembly_name == null) {
870+
return assembly_name_reference.FullName;
871+
} else {
872+
return assembly_name.FullName;
873+
}
874+
}
875+
}
876+
877+
public string Name {
878+
get {
879+
if (assembly_name == null) {
880+
return assembly_name_reference.Name;
881+
} else {
882+
return assembly_name.Name;
883+
}
884+
}
885+
}
886+
887+
public Version Version {
888+
get {
889+
if (assembly_name == null) {
890+
return assembly_name_reference.Version;
891+
} else {
892+
return assembly_name.Version;
893+
}
894+
}
895+
}
896+
897+
public byte [] PublicKeyToken {
898+
get {
899+
if (assembly_name == null) {
900+
return assembly_name_reference.PublicKeyToken;
901+
} else {
902+
return assembly_name.GetPublicKeyToken();
903+
}
904+
}
905+
}
906+
907+
public string Culture {
908+
get {
909+
if (assembly_name == null) {
910+
return assembly_name_reference.Culture;
911+
} else {
912+
return assembly_name.CultureInfo.Name;
913+
}
914+
}
915+
}
916+
917+
public static bool Equals (AssemblyNameWrapper a, AssemblyNameWrapper b, bool check_name_only)
918+
{
919+
if (ReferenceEquals (a, b))
920+
return true;
921+
if(a.assembly_name != null && ReferenceEquals(a.assembly_name, b.assembly_name))
922+
return true;
923+
if (a.assembly_name_reference != null && ReferenceEquals (a.assembly_name_reference, b.assembly_name_reference))
924+
return true;
925+
if (a.Name != b.Name)
926+
return false;
927+
928+
if (!check_name_only) {
929+
if (!Equals (a.Version, b.Version))
930+
return false;
931+
if (a.Culture != b.Culture)
932+
return false;
933+
if (!Equals (a.PublicKeyToken, b.PublicKeyToken))
934+
return false;
935+
}
936+
800937
return true;
801-
if (a.Name != b.Name)
802-
return false;
803-
if (!Equals (a.Version, b.Version))
804-
return false;
805-
if (a.Culture != b.Culture)
806-
return false;
807-
if (!Equals (a.PublicKeyToken, b.PublicKeyToken))
808-
return false;
809-
return true;
938+
}
939+
940+
public static implicit operator AssemblyNameWrapper (AssemblyName assembly_name)
941+
{
942+
return new AssemblyNameWrapper (assembly_name);
943+
}
944+
945+
public static implicit operator AssemblyNameWrapper (AssemblyNameReference assembly_name_reference)
946+
{
947+
return new AssemblyNameWrapper (assembly_name_reference);
948+
}
810949
}
811950
}
812951
}

0 commit comments

Comments
 (0)