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..d5cbbddbd 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,12 +288,25 @@ 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;
+ 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.
@@ -320,6 +334,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;