obfuz/Plugins/dnlib/DotNet/Resolver.cs

164 lines
5.3 KiB
C#
Raw Normal View History

// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
namespace dnlib.DotNet {
/// <summary>
/// Resolves types, methods, fields
/// </summary>
public sealed class Resolver : IResolver {
readonly IAssemblyResolver assemblyResolver;
/// <summary>
/// <c>true</c> to project WinMD types to CLR types, eg. <c>Windows.UI.Xaml.Interop.TypeName</c>
/// gets converted to <c>System.Type</c> before trying to resolve the type. This is enabled
/// by default.
/// </summary>
public bool ProjectWinMDRefs {
get => projectWinMDRefs;
set => projectWinMDRefs = value;
}
bool projectWinMDRefs = true;
/// <summary>
/// Constructor
/// </summary>
/// <param name="assemblyResolver">The assembly resolver</param>
public Resolver(IAssemblyResolver assemblyResolver) =>
this.assemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver));
/// <inheritdoc/>
public TypeDef Resolve(TypeRef typeRef, ModuleDef sourceModule) {
if (typeRef is null)
return null;
if (ProjectWinMDRefs)
typeRef = WinMDHelpers.ToCLR(typeRef.Module ?? sourceModule, typeRef) ?? typeRef;
var nonNestedTypeRef = TypeRef.GetNonNestedTypeRef(typeRef);
if (nonNestedTypeRef is null)
return null;
var nonNestedResolutionScope = nonNestedTypeRef.ResolutionScope;
var nonNestedModule = nonNestedTypeRef.Module;
if (nonNestedResolutionScope is AssemblyRef asmRef) {
var asm = assemblyResolver.Resolve(asmRef, sourceModule ?? nonNestedModule);
return asm is null ? null : asm.Find(typeRef) ?? ResolveExportedType(asm.Modules, typeRef, sourceModule);
}
if (nonNestedResolutionScope is ModuleDef moduleDef)
return moduleDef.Find(typeRef) ?? ResolveExportedType(new ModuleDef[] { moduleDef }, typeRef, sourceModule);
if (nonNestedResolutionScope is ModuleRef moduleRef) {
if (nonNestedModule is null)
return null;
if (new SigComparer().Equals(moduleRef, nonNestedModule))
return nonNestedModule.Find(typeRef) ??
ResolveExportedType(new ModuleDef[] { nonNestedModule }, typeRef, sourceModule);
var nonNestedAssembly = nonNestedModule.Assembly;
if (nonNestedAssembly is null)
return null;
var resolvedModule = nonNestedAssembly.FindModule(moduleRef.Name);
return resolvedModule is null ? null : resolvedModule.Find(typeRef) ??
ResolveExportedType(new ModuleDef[] { resolvedModule }, typeRef, sourceModule);
}
if (nonNestedResolutionScope is null) {
// ECMA II.22.38 states that in this case we should check ExportedTypes only.
// The CLR however checks both TypeDefs and ExportedTypes, with TypeDefs taking precedence.
return nonNestedModule.Find(typeRef) ?? ResolveExportedType(new ModuleDef[] { nonNestedModule }, typeRef, sourceModule);
}
return null;
}
TypeDef ResolveExportedType(IList<ModuleDef> modules, TypeRef typeRef, ModuleDef sourceModule) {
for (int i = 0; i < 30; i++) {
var exportedType = FindExportedType(modules, typeRef);
if (exportedType is null)
return null;
var asmResolver = modules[0].Context.AssemblyResolver;
var etAsm = asmResolver.Resolve(exportedType.DefinitionAssembly, sourceModule ?? typeRef.Module);
if (etAsm is null)
return null;
var td = etAsm.Find(typeRef);
if (td is not null)
return td;
modules = etAsm.Modules;
}
return null;
}
static ExportedType FindExportedType(IList<ModuleDef> modules, TypeRef typeRef) {
if (typeRef is null)
return null;
int count = modules.Count;
for (int i = 0; i < count; i++) {
var module = modules[i];
var exportedTypes = module.ExportedTypes;
int count2 = exportedTypes.Count;
for (int j = 0; j < count2; j++) {
var exportedType = exportedTypes[j];
if (new SigComparer(SigComparerOptions.DontCompareTypeScope).Equals(exportedType, typeRef))
return exportedType;
}
}
return null;
}
/// <inheritdoc/>
public IMemberForwarded Resolve(MemberRef memberRef) {
if (memberRef is null)
return null;
if (ProjectWinMDRefs)
memberRef = WinMDHelpers.ToCLR(memberRef.Module, memberRef) ?? memberRef;
var parent = memberRef.Class;
if (parent is MethodDef method)
return method;
return GetDeclaringType(memberRef, parent)?.Resolve(memberRef);
}
TypeDef GetDeclaringType(MemberRef memberRef, IMemberRefParent parent) {
if (memberRef is null || parent is null)
return null;
if (parent is TypeSpec ts)
parent = ts.ScopeType;
if (parent is TypeDef declaringTypeDef)
return declaringTypeDef;
if (parent is TypeRef declaringTypeRef)
return Resolve(declaringTypeRef, memberRef.Module);
// A module ref is used to reference the global type of a module in the same
// assembly as the current module.
if (parent is ModuleRef moduleRef) {
var module = memberRef.Module;
if (module is null)
return null;
TypeDef globalType = null;
if (new SigComparer().Equals(module, moduleRef))
globalType = module.GlobalType;
var modAsm = module.Assembly;
if (globalType is null && modAsm is not null) {
var moduleDef = modAsm.FindModule(moduleRef.Name);
if (moduleDef is not null)
globalType = moduleDef.GlobalType;
}
return globalType;
}
if (parent is MethodDef method)
return method.DeclaringType;
return null;
}
}
}