From 188bac4e550dc372a03c506056a1508542d6cd95 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 24 Nov 2018 14:18:49 +0100 Subject: [PATCH 1/2] Possible fix for primitive types resolving to MinimalCorlib types in navigateTo handling. --- .../GetPotentiallyNestedClassTypeReference.cs | 48 ++++++++++++++- ICSharpCode.Decompiler/SRMExtensions.cs | 9 ++- ILSpy/MainWindow.xaml.cs | 60 ++++++++++++++++--- 3 files changed, 107 insertions(+), 10 deletions(-) diff --git a/ICSharpCode.Decompiler/Documentation/GetPotentiallyNestedClassTypeReference.cs b/ICSharpCode.Decompiler/Documentation/GetPotentiallyNestedClassTypeReference.cs index 4394157f0..46b11db6c 100644 --- a/ICSharpCode.Decompiler/Documentation/GetPotentiallyNestedClassTypeReference.cs +++ b/ICSharpCode.Decompiler/Documentation/GetPotentiallyNestedClassTypeReference.cs @@ -18,6 +18,8 @@ using System; using System.Linq; +using System.Reflection.Metadata; +using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; @@ -30,7 +32,7 @@ namespace ICSharpCode.Decompiler.Documentation /// The type parameter count only applies to the innermost type, all outer types must be non-generic. /// [Serializable] - class GetPotentiallyNestedClassTypeReference : ITypeReference + public class GetPotentiallyNestedClassTypeReference : ITypeReference { readonly string typeName; readonly int typeParameterCount; @@ -67,5 +69,49 @@ namespace ICSharpCode.Decompiler.Documentation // give back a guessed namespace/type name return new UnknownType(typeName.Substring(0, idx), typeName.Substring(idx + 1), typeParameterCount); } + + /// + /// Resolves the type reference within the context of the given PE file. + /// + /// 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. + 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; + + bool IsEqualShortName(TypeDefinitionHandle h, MetadataReader metadata, string name) + { + var nestedType = metadata.GetTypeDefinition(h); + return metadata.StringComparer.Equals(nestedType.Name, name); + } + } } } diff --git a/ICSharpCode.Decompiler/SRMExtensions.cs b/ICSharpCode.Decompiler/SRMExtensions.cs index cb43e3691..07600038a 100644 --- a/ICSharpCode.Decompiler/SRMExtensions.cs +++ b/ICSharpCode.Decompiler/SRMExtensions.cs @@ -241,9 +241,14 @@ namespace ICSharpCode.Decompiler public static FullTypeName GetFullTypeName(this ExportedType type, MetadataReader metadata) { - string ns = type.Namespace.IsNil ? "" : metadata.GetString(type.Namespace); string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(metadata.GetString(type.Name), out int typeParameterCount); - return new TopLevelTypeName(ns, name, typeParameterCount); + if (type.Implementation.Kind == HandleKind.ExportedType) { + var outerType = metadata.GetExportedType((ExportedTypeHandle)type.Implementation); + return outerType.GetFullTypeName(metadata).NestedType(name, typeParameterCount); + } else { + string ns = type.Namespace.IsNil ? "" : metadata.GetString(type.Namespace); + return new TopLevelTypeName(ns, name, typeParameterCount); + } } public static bool IsAnonymousType(this TypeDefinition type, MetadataReader metadata) diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 0b0add19a..48a25ddb8 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -23,6 +23,7 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection.Metadata; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; @@ -287,15 +288,36 @@ namespace ICSharpCode.ILSpy } } } else { + ITypeReference typeRef = null; + IMemberReference memberRef = null; + if (args.NavigateTo.StartsWith("T:", StringComparison.Ordinal)) { + typeRef = IdStringProvider.ParseTypeName(args.NavigateTo); + } else { + memberRef = IdStringProvider.ParseMemberIdString(args.NavigateTo); + typeRef = memberRef.DeclaringTypeReference; + } foreach (LoadedAssembly asm in commandLineLoadedAssemblies) { - var def = asm.GetPEFileOrNull(); - if (def != null) { - var compilation = new SimpleCompilation(def, MinimalCorlib.Instance); - var mr = IdStringProvider.FindEntity(args.NavigateTo, new SimpleTypeResolveContext(compilation)); - if (mr != null) { + var module = asm.GetPEFileOrNull(); + if (CanResolveTypeInPEFile(module, typeRef, out var typeHandle)) { + IEntity mr = null; + if (typeHandle.Kind == HandleKind.ExportedType) { + var decompilerTypeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); + if (memberRef == null) { + mr = typeRef.Resolve(new SimpleTypeResolveContext(decompilerTypeSystem)) as ITypeDefinition; + } else { + mr = memberRef.Resolve(new SimpleTypeResolveContext(decompilerTypeSystem)); + } + } else { + var compilation = new SimpleCompilation(module, MinimalCorlib.Instance); + if (memberRef == null) { + mr = ((MetadataModule)compilation.MainModule).GetDefinition((TypeDefinitionHandle)typeHandle); + } else { + mr = memberRef.Resolve(new SimpleTypeResolveContext(compilation)); + } + } + + if (mr != null && mr.ParentModule.PEFile != null) { found = true; - // Defer JumpToReference call to allow an assembly that was loaded while - // resolving a type-forwarder in FindMemberByKey to appear in the assembly list. Dispatcher.BeginInvoke(new Action(() => JumpToReference(mr)), DispatcherPriority.Loaded); break; } @@ -320,6 +342,30 @@ namespace ICSharpCode.ILSpy commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore } + private bool CanResolveTypeInPEFile(PEFile module, ITypeReference typeRef, out EntityHandle typeHandle) + { + switch (typeRef) { + case GetPotentiallyNestedClassTypeReference topLevelType: + typeHandle = topLevelType.ResolveInPEFile(module); + return !typeHandle.IsNil; + case NestedTypeReference nestedType: + if (!CanResolveTypeInPEFile(module, nestedType.DeclaringTypeReference, out typeHandle)) + return false; + if (typeHandle.Kind == HandleKind.ExportedType) + return true; + var typeDef = module.Metadata.GetTypeDefinition((TypeDefinitionHandle)typeHandle); + typeHandle = typeDef.GetNestedTypes().FirstOrDefault(t => { + var td = module.Metadata.GetTypeDefinition(t); + var typeName = ReflectionHelper.SplitTypeParameterCountFromReflectionName(module.Metadata.GetString(td.Name), out int typeParameterCount); + return nestedType.AdditionalTypeParameterCount == typeParameterCount && nestedType.Name == typeName; + }); + return !typeHandle.IsNil; + default: + typeHandle = default; + return false; + } + } + void MainWindow_Loaded(object sender, RoutedEventArgs e) { ILSpySettings spySettings = this.spySettings; From c73f46d27c7c496052c7cc3ff8a7d642372c34b2 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 24 Nov 2018 16:35:20 +0100 Subject: [PATCH 2/2] Refactor code in HandleCommandLineArgumentsAfterShowList as per code-review. --- ILSpy/MainWindow.xaml.cs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 48a25ddb8..d5cbbddbd 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -300,24 +300,16 @@ namespace ICSharpCode.ILSpy var module = asm.GetPEFileOrNull(); if (CanResolveTypeInPEFile(module, typeRef, out var typeHandle)) { IEntity mr = null; - if (typeHandle.Kind == HandleKind.ExportedType) { - var decompilerTypeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); - if (memberRef == null) { - mr = typeRef.Resolve(new SimpleTypeResolveContext(decompilerTypeSystem)) as ITypeDefinition; - } else { - mr = memberRef.Resolve(new SimpleTypeResolveContext(decompilerTypeSystem)); - } - } else { - var compilation = new SimpleCompilation(module, MinimalCorlib.Instance); - if (memberRef == null) { - mr = ((MetadataModule)compilation.MainModule).GetDefinition((TypeDefinitionHandle)typeHandle); - } else { - mr = memberRef.Resolve(new SimpleTypeResolveContext(compilation)); - } - } - + ICompilation compilation = typeHandle.Kind == HandleKind.ExportedType + ? new DecompilerTypeSystem(module, module.GetAssemblyResolver()) + : new SimpleCompilation(module, MinimalCorlib.Instance); + mr = memberRef == null + ? typeRef.Resolve(new SimpleTypeResolveContext(compilation)) as ITypeDefinition + : (IEntity)memberRef.Resolve(new SimpleTypeResolveContext(compilation)); if (mr != null && mr.ParentModule.PEFile != null) { found = true; + // Defer JumpToReference call to allow an assembly that was loaded while + // resolving a type-forwarder in FindMemberByKey to appear in the assembly list. Dispatcher.BeginInvoke(new Action(() => JumpToReference(mr)), DispatcherPriority.Loaded); break; }