public ITypeDefinition GetTypeDefinition(TopLevelTypeName topLevelTypeName) { var typeDefHandle = PEFile.GetTypeDefinition(topLevelTypeName); if (typeDefHandle.IsNil) { var forwarderHandle = PEFile.GetTypeForwarder(topLevelTypeName); if (!forwarderHandle.IsNil) { var forwarder = metadata.GetExportedType(forwarderHandle); return(ResolveForwardedType(forwarder).GetDefinition()); } } return(GetDefinition(typeDefHandle)); }
/// <summary> /// Resolves the type reference within the context of the given PE file. /// </summary> /// <returns>Either TypeDefinitionHandle, if the type is defined in the module or ExportedTypeHandle, /// if the module contains a type forwarder. Returns a nil handle, if the type was not found.</returns> public EntityHandle ResolveInPEFile(PEFile module) { string[] parts = typeName.Split('.'); for (int i = parts.Length - 1; i >= 0; i--) { string ns = string.Join(".", parts, 0, i); string name = parts[i]; int topLevelTPC = (i == parts.Length - 1 ? typeParameterCount : 0); var topLevelName = new TopLevelTypeName(ns, name, topLevelTPC); var typeHandle = module.GetTypeDefinition(topLevelName); for (int j = i + 1; j < parts.Length && !typeHandle.IsNil; j++) { int tpc = (j == parts.Length - 1 ? typeParameterCount : 0); var typeDef = module.Metadata.GetTypeDefinition(typeHandle); string lookupName = parts[j] + (tpc > 0 ? "`" + tpc : ""); typeHandle = typeDef.GetNestedTypes().FirstOrDefault(n => IsEqualShortName(n, module.Metadata, lookupName)); } if (!typeHandle.IsNil) { return(typeHandle); } FullTypeName typeName = topLevelName; for (int j = i + 1; j < parts.Length; j++) { int tpc = (j == parts.Length - 1 ? typeParameterCount : 0); typeName = typeName.NestedType(parts[j], tpc); } var exportedType = module.GetTypeForwarder(typeName); if (!exportedType.IsNil) { return(exportedType); } } return(default);
public BamlDecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver) { if (mainModule == null) { throw new ArgumentNullException(nameof(mainModule)); } if (assemblyResolver == null) { throw new ArgumentNullException(nameof(assemblyResolver)); } // Load referenced assemblies and type-forwarder references. // This is necessary to make .NET Core/PCL binaries work better. var referencedAssemblies = new List <PEFile>(); var assemblyReferenceQueue = new Queue <(bool IsAssembly, PEFile MainModule, object Reference)>(); var mainMetadata = mainModule.Metadata; foreach (var h in mainMetadata.GetModuleReferences()) { var moduleRef = mainMetadata.GetModuleReference(h); var moduleName = mainMetadata.GetString(moduleRef.Name); foreach (var fileHandle in mainMetadata.AssemblyFiles) { var file = mainMetadata.GetAssemblyFile(fileHandle); if (mainMetadata.StringComparer.Equals(file.Name, moduleName) && file.ContainsMetadata) { assemblyReferenceQueue.Enqueue((false, mainModule, moduleName)); break; } } } foreach (var refs in mainModule.AssemblyReferences) { assemblyReferenceQueue.Enqueue((true, mainModule, refs)); } foreach (var bamlReference in defaultBamlReferences) { assemblyReferenceQueue.Enqueue((true, mainModule, AssemblyNameReference.Parse(bamlReference))); } var comparer = KeyComparer.Create(((bool IsAssembly, PEFile MainModule, object Reference)reference) => reference.IsAssembly ? "A:" + ((IAssemblyReference)reference.Reference).FullName : "M:" + reference.Reference); var processedAssemblyReferences = new HashSet <(bool IsAssembly, PEFile Parent, object Reference)>(comparer); while (assemblyReferenceQueue.Count > 0) { var asmRef = assemblyReferenceQueue.Dequeue(); if (!processedAssemblyReferences.Add(asmRef)) { continue; } PEFile asm; if (asmRef.IsAssembly) { asm = assemblyResolver.Resolve((IAssemblyReference)asmRef.Reference); } else { asm = assemblyResolver.ResolveModule(asmRef.MainModule, (string)asmRef.Reference); } if (asm != null) { referencedAssemblies.Add(asm); var metadata = asm.Metadata; foreach (var h in metadata.ExportedTypes) { var exportedType = metadata.GetExportedType(h); switch (exportedType.Implementation.Kind) { case SRM.HandleKind.AssemblyReference: assemblyReferenceQueue.Enqueue((true, asm, new AssemblyReference(asm, (SRM.AssemblyReferenceHandle)exportedType.Implementation))); break; case SRM.HandleKind.AssemblyFile: var file = metadata.GetAssemblyFile((SRM.AssemblyFileHandle)exportedType.Implementation); assemblyReferenceQueue.Enqueue((false, asm, metadata.GetString(file.Name))); break; } } } } var mainModuleWithOptions = mainModule.WithOptions(TypeSystemOptions.Default); var referencedAssembliesWithOptions = referencedAssemblies.Select(file => file.WithOptions(TypeSystemOptions.Default)); // Primitive types are necessary to avoid assertions in ILReader. // Fallback to MinimalCorlib to provide the primitive types. if (!HasType(KnownTypeCode.Void) || !HasType(KnownTypeCode.Int32)) { Init(mainModule.WithOptions(TypeSystemOptions.Default), referencedAssembliesWithOptions.Concat(new[] { MinimalCorlib.Instance })); } else { Init(mainModuleWithOptions, referencedAssembliesWithOptions); } this.MainModule = (MetadataModule)base.MainModule; bool HasType(KnownTypeCode code) { TopLevelTypeName name = KnownTypeReference.Get(code).TypeName; if (mainModule.GetTypeDefinition(name) != null) { return(true); } foreach (var file in referencedAssemblies) { if (file.GetTypeDefinition(name) != null) { return(true); } } return(false); } }