From 47788a38decf5ed3e559b56d81aae13ae827e17b Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 31 May 2018 14:51:24 +0200 Subject: [PATCH] WIP --- .../CSharp/RequiredNamespaceCollector.cs | 14 +- .../Metadata/MetadataResolver.cs | 106 ++++---- .../Metadata/OperandType.cs | 2 +- .../Output/TextTokenWriter.cs | 10 +- ICSharpCode.Decompiler/SRMExtensions.cs | 23 ++ .../TypeSystem/DecompilerTypeSystem.cs | 15 +- .../TypeSystem/IDecompilerTypeSystem.cs | 1 + .../Implementation/DefaultUnresolvedMethod.cs | 1 + .../SpecializingDecompilerTypeSystem.cs | 6 + ILSpy/ILSpy.csproj | 17 ++ ILSpy/Languages/CSharpLanguage.cs | 76 +++++- ILSpy/Languages/CodeMappingInfo.cs | 63 +++++ ILSpy/Languages/ILSignatureProvider.cs | 172 ++++++++++++ ILSpy/Languages/Language.cs | 175 ++---------- ILSpy/MainWindow.xaml.cs | 13 +- .../Analyzer/AnalyzeContextMenuEntry.cs | 107 +++++--- .../Analyzer/AnalyzedAssemblyTreeNode.cs | 4 +- .../Analyzer/AnalyzedEventTreeNode.cs | 28 +- .../Analyzer/AnalyzedFieldAccessTreeNode.cs | 93 ++++--- .../Analyzer/AnalyzedFieldTreeNode.cs | 31 +-- ...zedInterfaceMethodImplementedByTreeNode.cs | 5 +- .../Analyzer/AnalyzedMethodTreeNode.cs | 34 +-- .../Analyzer/AnalyzedMethodUsesTreeNode.cs | 122 +++++---- .../AnalyzedPropertyAccessorTreeNode.cs | 6 +- .../Analyzer/AnalyzedPropertyTreeNode.cs | 57 ++-- .../Analyzer/AnalyzedTypeExposedByTreeNode.cs | 15 +- .../AnalyzedTypeInstantiationsTreeNode.cs | 122 ++++++--- .../Analyzer/AnalyzedTypeTreeNode.cs | 45 ++-- .../Analyzer/AnalyzedTypeUsedByTreeNode.cs | 249 +++++++++++------- .../Analyzer/AnalyzerEntityTreeNode.cs | 1 + .../Analyzer/AnalyzerSearchTreeNode.cs | 3 - ILSpy/TreeNodes/Analyzer/Extensions.cs | 43 +++ .../Analyzer/ScopedWhereUsedAnalyzer.cs | 128 +++++---- .../CopyFullyQualifiedNameContextMenuEntry.cs | 49 +++- ILSpy/TreeNodes/TypeTreeNode.cs | 5 +- 35 files changed, 1163 insertions(+), 678 deletions(-) create mode 100644 ILSpy/Languages/CodeMappingInfo.cs create mode 100644 ILSpy/Languages/ILSignatureProvider.cs create mode 100644 ILSpy/TreeNodes/Analyzer/Extensions.cs diff --git a/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs b/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs index aa07aac2c..0db8ea38b 100644 --- a/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs +++ b/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs @@ -174,7 +174,7 @@ namespace ICSharpCode.Decompiler.CSharp if (handle.Kind.IsTypeKind()) CollectNamespacesForTypeReference(typeSystem.ResolveAsType(handle), namespaces); else - CollectNamespacesForMemberReference(typeSystem.ResolveAsMember(handle), namespaces); + CollectNamespacesForMemberReference(typeSystem.ResolveAsMember(handle), typeSystem, namespaces); break; default: instructions.SkipOperand(opCode); @@ -183,15 +183,21 @@ namespace ICSharpCode.Decompiler.CSharp } } - static void CollectNamespacesForMemberReference(IMember member, HashSet namespaces) + static void CollectNamespacesForMemberReference(IMember member, DecompilerTypeSystem typeSystem, HashSet namespaces) { switch (member) { case IField field: - CollectNamespacesForTypeReference(field.DeclaringType, namespaces); + if (field.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) + CollectNamespaces(field, typeSystem, namespaces); + else + CollectNamespacesForTypeReference(field.DeclaringType, namespaces); CollectNamespacesForTypeReference(field.ReturnType, namespaces); break; case IMethod method: - CollectNamespacesForTypeReference(method.DeclaringType, namespaces); + if (method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) + CollectNamespaces(method, typeSystem, namespaces); + else + CollectNamespacesForTypeReference(method.DeclaringType, namespaces); CollectNamespacesForTypeReference(method.ReturnType, namespaces); foreach (var param in method.Parameters) CollectNamespacesForTypeReference(param.Type, namespaces); diff --git a/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs b/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs index 2066aea62..3efc4c159 100644 --- a/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs +++ b/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs @@ -76,6 +76,11 @@ namespace ICSharpCode.Decompiler.Metadata if (resolved is MethodDefinition m) return m; return default; + case HandleKind.MethodSpecification: + resolved = ((MethodSpecificationHandle)handle).Resolve(context); + if (resolved is MethodDefinition m2) + return m2; + return default; } throw new NotImplementedException(); } @@ -155,7 +160,7 @@ namespace ICSharpCode.Decompiler.Metadata var currentNamespace = metadata.GetNamespaceDefinitionRoot(); for (int i = 0; i < namespaceParts.Length; i++) { string identifier = namespaceParts[i]; - var next = currentNamespace.NamespaceDefinitions.FirstOrDefault(ns => metadata.GetString(metadata.GetNamespaceDefinition(ns).Name) == identifier); + var next = currentNamespace.NamespaceDefinitions.FirstOrDefault(ns => metadata.StringComparer.Equals(ns, identifier)); if (next.IsNil) return null; currentNamespace = metadata.GetNamespaceDefinition(next); @@ -166,8 +171,7 @@ namespace ICSharpCode.Decompiler.Metadata static TypeDefinitionHandle FindTypeInNamespace(MetadataReader metadata, NamespaceDefinition @namespace, string name) { foreach (var type in @namespace.TypeDefinitions) { - var typeName = metadata.GetString(metadata.GetTypeDefinition(type).Name); - if (name == typeName) + if (metadata.StringComparer.Equals(metadata.GetTypeDefinition(type).Name, name)) return type; } return default; @@ -223,7 +227,7 @@ namespace ICSharpCode.Decompiler.Metadata if (candidates.Count == 0) throw new NotSupportedException(); foreach (var (method, signature) in candidates) { - if (SignatureBlobComparer.EqualsMethodSignature(targetMetadata.GetBlobReader(signature), metadata.GetBlobReader(mr.Signature), new SimpleMetadataResolveContext(targetModule, context), context)) + if (SignatureBlobComparer.EqualsMethodSignature(targetMetadata.GetBlobReader(signature), metadata.GetBlobReader(mr.Signature), targetMetadata, metadata)) return new MethodDefinition(targetModule, method); } throw new NotSupportedException(); @@ -246,6 +250,13 @@ namespace ICSharpCode.Decompiler.Metadata } } + public static MethodDefinition Resolve(this MethodSpecificationHandle handle, IMetadataResolveContext context) + { + var metadata = context.CurrentModule.Metadata; + var ms = metadata.GetMethodSpecification(handle); + return ResolveAsMethod(ms.Method, context); + } + class Unspecializer : ISignatureTypeProvider { public EntityHandle GetArrayType(EntityHandle elementType, ArrayShape shape) @@ -322,12 +333,12 @@ namespace ICSharpCode.Decompiler.Metadata public static class SignatureBlobComparer { - public static bool EqualsMethodSignature(BlobReader a, BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB) + public static bool EqualsMethodSignature(BlobReader a, BlobReader b, MetadataReader contextForA, MetadataReader contextForB) { return EqualsMethodSignature(ref a, ref b, contextForA, contextForB); } - static bool EqualsMethodSignature(ref BlobReader a, ref BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB) + static bool EqualsMethodSignature(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB) { SignatureHeader header; // compare signature headers @@ -349,6 +360,7 @@ namespace ICSharpCode.Decompiler.Metadata for (; i < totalParameterCount; i++) { if (!IsSameCompressedInteger(ref a, ref b, out typeCode)) return false; + // if (typeCode == 65) break; if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode)) @@ -365,50 +377,50 @@ namespace ICSharpCode.Decompiler.Metadata static bool IsSameCompressedInteger(ref BlobReader a, ref BlobReader b, out int value) { - return a.TryReadCompressedInteger(out value) == b.TryReadCompressedInteger(out int otherValue) && value == otherValue; + return a.TryReadCompressedInteger(out value) && b.TryReadCompressedInteger(out int otherValue) && value == otherValue; } static bool IsSameCompressedSignedInteger(ref BlobReader a, ref BlobReader b, out int value) { - return a.TryReadCompressedSignedInteger(out value) == b.TryReadCompressedSignedInteger(out int otherValue) && value == otherValue; + return a.TryReadCompressedSignedInteger(out value) && b.TryReadCompressedSignedInteger(out int otherValue) && value == otherValue; } - static bool TypesAreEqual(ref BlobReader a, ref BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB, int typeCode) + static bool TypesAreEqual(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB, int typeCode) { switch (typeCode) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 22: - case 24: - case 25: - case 28: // primitive types + case 0x1: // ELEMENT_TYPE_VOID + case 0x2: // ELEMENT_TYPE_BOOLEAN + case 0x3: // ELEMENT_TYPE_CHAR + case 0x4: // ELEMENT_TYPE_I1 + case 0x5: // ELEMENT_TYPE_U1 + case 0x6: // ELEMENT_TYPE_I2 + case 0x7: // ELEMENT_TYPE_U2 + case 0x8: // ELEMENT_TYPE_I4 + case 0x9: // ELEMENT_TYPE_U4 + case 0xA: // ELEMENT_TYPE_I8 + case 0xB: // ELEMENT_TYPE_U8 + case 0xC: // ELEMENT_TYPE_R4 + case 0xD: // ELEMENT_TYPE_R8 + case 0xE: // ELEMENT_TYPE_STRING + case 0x16: // ELEMENT_TYPE_TYPEDBYREF + case 0x18: // ELEMENT_TYPE_I + case 0x19: // ELEMENT_TYPE_U + case 0x1C: // ELEMENT_TYPE_OBJECT return true; - case 15: // pointer type - case 16: // byref type - case 69: // pinned type - case 29: // szarray type + case 0xF: // ELEMENT_TYPE_PTR + case 0x10: // ELEMENT_TYPE_BYREF + case 0x45: // ELEMENT_TYPE_PINNED + case 0x1D: // ELEMENT_TYPE_SZARRAY if (!IsSameCompressedInteger(ref a, ref b, out typeCode)) return false; if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode)) return false; return true; - case 27: + case 0x1B: // ELEMENT_TYPE_FNPTR if (!EqualsMethodSignature(ref a, ref b, contextForA, contextForB)) return false; return true; - case 20: // array type + case 0x14: // ELEMENT_TYPE_ARRAY // element type if (!IsSameCompressedInteger(ref a, ref b, out typeCode)) return false; @@ -424,7 +436,7 @@ namespace ICSharpCode.Decompiler.Metadata if (!IsSameCompressedInteger(ref a, ref b, out _)) return false; } - // lowerBounds + // lower bounds if (!IsSameCompressedInteger(ref a, ref b, out int numOfLowerBounds)) return false; for (int i = 0; i < numOfLowerBounds; i++) { @@ -432,8 +444,8 @@ namespace ICSharpCode.Decompiler.Metadata return false; } return true; - case 31: // mod-req type - case 32: // mod-opt type + case 0x1F: // ELEMENT_TYPE_CMOD_REQD + case 0x20: // ELEMENT_TYPE_CMOD_OPT // modifier if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB)) return false; @@ -443,7 +455,7 @@ namespace ICSharpCode.Decompiler.Metadata if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode)) return false; return true; - case 21: // generic instance type + case 0x15: // ELEMENT_TYPE_GENERICINST // generic type if (!IsSameCompressedInteger(ref a, ref b, out typeCode)) return false; @@ -458,14 +470,14 @@ namespace ICSharpCode.Decompiler.Metadata return false; } return true; - case 19: // type parameter - case 30: // method type parameter + case 0x13: // ELEMENT_TYPE_VAR + case 0x1E: // ELEMENT_TYPE_MVAR // index if (!IsSameCompressedInteger(ref a, ref b, out _)) return false; return true; - case 17: - case 18: + case 0x11: // ELEMENT_TYPE_VALUETYPE + case 0x12: // ELEMENT_TYPE_CLASS if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB)) return false; return true; @@ -474,21 +486,13 @@ namespace ICSharpCode.Decompiler.Metadata } } - static bool TypeHandleEquals(ref BlobReader a, ref BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB) + static bool TypeHandleEquals(ref BlobReader a, ref BlobReader b, MetadataReader contextForA, MetadataReader contextForB) { var typeA = a.ReadTypeHandle(); var typeB = b.ReadTypeHandle(); if (typeA.IsNil || typeB.IsNil) return false; - var resolvedA = MetadataResolver.ResolveType(typeA, contextForA); - var resolvedB = MetadataResolver.ResolveType(typeB, contextForB); - if (resolvedA.IsNil || resolvedB.IsNil) - return false; - if (resolvedA.Handle != resolvedB.Handle) - return false; - if (resolvedA.Module.FullName != resolvedB.Module.FullName) - return false; - return true; + return typeA.GetFullTypeName(contextForA) == typeB.GetFullTypeName(contextForB); } } } diff --git a/ICSharpCode.Decompiler/Metadata/OperandType.cs b/ICSharpCode.Decompiler/Metadata/OperandType.cs index da17acee1..8a8e7e0fc 100644 --- a/ICSharpCode.Decompiler/Metadata/OperandType.cs +++ b/ICSharpCode.Decompiler/Metadata/OperandType.cs @@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.Metadata ShortVariable } - static partial class ILOpCodeExtensions + public static partial class ILOpCodeExtensions { public static OperandType GetOperandType(this ILOpCode opCode) { diff --git a/ICSharpCode.Decompiler/Output/TextTokenWriter.cs b/ICSharpCode.Decompiler/Output/TextTokenWriter.cs index 8973cf71b..68ec3cb33 100644 --- a/ICSharpCode.Decompiler/Output/TextTokenWriter.cs +++ b/ICSharpCode.Decompiler/Output/TextTokenWriter.cs @@ -106,15 +106,15 @@ namespace ICSharpCode.Decompiler var definition = type.GetDefinition(); if (definition == null) return null; - return new TypeDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.TypeDefinitionHandle)definition.MetadataToken); + return new TypeDefinition(typeSystem.GetModuleDefinition(definition.ParentAssembly), (System.Reflection.Metadata.TypeDefinitionHandle)definition.MetadataToken); case IMethod method: - return new MethodDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.MethodDefinitionHandle)method.MetadataToken); + return new MethodDefinition(typeSystem.GetModuleDefinition(method.ParentAssembly), (System.Reflection.Metadata.MethodDefinitionHandle)method.MetadataToken); case IProperty property: - return new PropertyDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.PropertyDefinitionHandle)property.MetadataToken); + return new PropertyDefinition(typeSystem.GetModuleDefinition(property.ParentAssembly), (System.Reflection.Metadata.PropertyDefinitionHandle)property.MetadataToken); case IEvent @event: - return new EventDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.EventDefinitionHandle)@event.MetadataToken); + return new EventDefinition(typeSystem.GetModuleDefinition(@event.ParentAssembly), (System.Reflection.Metadata.EventDefinitionHandle)@event.MetadataToken); case IField field: - return new FieldDefinition(typeSystem.ModuleDefinition, (System.Reflection.Metadata.FieldDefinitionHandle)field.MetadataToken); + return new FieldDefinition(typeSystem.GetModuleDefinition(field.ParentAssembly), (System.Reflection.Metadata.FieldDefinitionHandle)field.MetadataToken); default: return null; } diff --git a/ICSharpCode.Decompiler/SRMExtensions.cs b/ICSharpCode.Decompiler/SRMExtensions.cs index 262e0e9aa..a971e4731 100644 --- a/ICSharpCode.Decompiler/SRMExtensions.cs +++ b/ICSharpCode.Decompiler/SRMExtensions.cs @@ -134,6 +134,29 @@ namespace ICSharpCode.Decompiler return accessors.Raiser; } + public static TypeDefinitionHandle GetDeclaringType(this EntityHandle entity, MetadataReader metadata) + { + switch (entity.Kind) { + case HandleKind.TypeDefinition: + var td = metadata.GetTypeDefinition((TypeDefinitionHandle)entity); + return td.GetDeclaringType(); + case HandleKind.FieldDefinition: + var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)entity); + return fd.GetDeclaringType(); + case HandleKind.MethodDefinition: + var md = metadata.GetMethodDefinition((MethodDefinitionHandle)entity); + return md.GetDeclaringType(); + case HandleKind.EventDefinition: + var ed = metadata.GetEventDefinition((EventDefinitionHandle)entity); + return metadata.GetMethodDefinition(ed.GetAccessors().GetAny()).GetDeclaringType(); + case HandleKind.PropertyDefinition: + var pd = metadata.GetPropertyDefinition((PropertyDefinitionHandle)entity); + return metadata.GetMethodDefinition(pd.GetAccessors().GetAny()).GetDeclaringType(); + default: + throw new ArgumentOutOfRangeException(); + } + } + public static TypeReferenceHandle GetDeclaringType(this TypeReference tr) { switch (tr.ResolutionScope.Kind) { diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs index 83b12903f..873357f1f 100644 --- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs @@ -32,6 +32,8 @@ namespace ICSharpCode.Decompiler.TypeSystem Dictionary propertyLookupCache = new Dictionary(); Dictionary methodLookupCache = new Dictionary(); Dictionary eventLookupCache = new Dictionary(); + + Dictionary moduleLookup = new Dictionary(); public DecompilerTypeSystem(Metadata.PEFile moduleDefinition) { @@ -52,7 +54,9 @@ namespace ICSharpCode.Decompiler.TypeSystem continue; var asm = moduleDefinition.AssemblyResolver.Resolve(asmRef); if (asm != null) { - referencedAssemblies.Add(cecilLoader.LoadModule(asm)); + IUnresolvedAssembly unresolvedAsm = cecilLoader.LoadModule(asm); + referencedAssemblies.Add(unresolvedAsm); + moduleLookup.Add(unresolvedAsm, asm); var metadata = asm.Metadata; foreach (var h in metadata.ExportedTypes) { var forwarder = metadata.GetExportedType(h); @@ -85,6 +89,15 @@ namespace ICSharpCode.Decompiler.TypeSystem public SRM.MetadataReader GetMetadata() => moduleDefinition.Metadata; + public Metadata.PEFile GetModuleDefinition(IAssembly assembly) + { + if (assembly == MainAssembly) + return ModuleDefinition; + if (!moduleLookup.TryGetValue(assembly.UnresolvedAssembly, out var file)) + return null; + return file; + } + public IType ResolveFromSignature(ITypeReference typeReference) { return typeReference.Resolve(context); diff --git a/ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs index 427712021..f1865c4f5 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs @@ -36,6 +36,7 @@ namespace ICSharpCode.Decompiler.TypeSystem MetadataReader GetMetadata(); PEFile ModuleDefinition { get; } + PEFile GetModuleDefinition(IAssembly assembly); /// /// Gets a type system instance that automatically specializes the results diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs index 142e72470..c7126664f 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedMethod.cs @@ -223,6 +223,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation Accessibility = typeDefinition.IsAbstract ? Accessibility.Protected : Accessibility.Public, IsSynthetic = true, HasBody = true, + MetadataToken = System.Reflection.Metadata.Ecma335.MetadataTokens.MethodDefinitionHandle(0), // initialize with properly typed nil token, to avoid InvalidCastExceptions ReturnType = KnownTypeReference.Void }; } diff --git a/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs index 02a91c082..68c76762b 100644 --- a/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.Decompiler.TypeSystem { @@ -99,5 +100,10 @@ namespace ICSharpCode.Decompiler.TypeSystem member = member.Specialize(substitution); return member; } + + public PEFile GetModuleDefinition(IAssembly assembly) + { + return context.GetModuleDefinition(assembly); + } } } diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 20bc2b973..c485b4776 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -111,6 +111,7 @@ DebugSteps.xaml + @@ -131,6 +132,7 @@ + @@ -186,8 +188,23 @@ + + + + + + + + + + + + + + + diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 088b217a6..509f45564 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -40,6 +40,7 @@ using System.Reflection.Metadata.Ecma335; using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.Util; using System.Reflection; +using ICSharpCode.Decompiler.Disassembler; namespace ICSharpCode.ILSpy { @@ -601,7 +602,17 @@ namespace ICSharpCode.ILSpy convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName; var metadata = method.Module.Metadata; var md = metadata.GetMethodDefinition(method.Handle); - var name = (md.IsConstructor(metadata)) ? TypeToString(new Decompiler.Metadata.TypeDefinition(method.Module, md.GetDeclaringType()), includeNamespace: includeNamespace) : metadata.GetString(md.Name); + string name; + if (md.IsConstructor(metadata)) { + name = TypeToString(new Decompiler.Metadata.TypeDefinition(method.Module, md.GetDeclaringType()), includeNamespace: includeNamespace); + } else { + if (includeTypeName) { + name = TypeToString(new Decompiler.Metadata.TypeDefinition(method.Module, md.GetDeclaringType()), includeNamespace: includeNamespace) + "."; + } else { + name = ""; + } + name += metadata.GetString(md.Name); + } var signature = md.DecodeSignature(new AstTypeBuilder(convertTypeOptions), new GenericContext(method)); int i = 0; @@ -692,16 +703,6 @@ namespace ICSharpCode.ILSpy return showAllMembers || !CSharpDecompiler.MemberIsHidden(member.Module, member.Handle, new DecompilationOptions().DecompilerSettings); } - /* - public override IMetadataEntity GetOriginalCodeLocation(IMetadataEntity member) - { - if (showAllMembers || !new DecompilationOptions().DecompilerSettings.AnonymousMethods) - return member; - else - return TreeNodes.Analyzer.Helpers.GetOriginalCodeLocation(member); - } - */ - public override string GetTooltip(Entity entity) { var decompilerTypeSystem = new DecompilerTypeSystem(entity.Module); @@ -733,6 +734,59 @@ namespace ICSharpCode.ILSpy var flags = ConversionFlags.All & ~ConversionFlags.ShowBody; return new CSharpAmbience() { ConversionFlags = flags }.ConvertSymbol(symbol); } + + public override CodeMappingInfo GetCodeMappingInfo(PEFile module, EntityHandle member) + { + var declaringType = member.GetDeclaringType(module.Metadata); + + if (declaringType.IsNil && member.Kind == HandleKind.TypeDefinition) { + declaringType = (TypeDefinitionHandle)member; + } + + var info = new CodeMappingInfo(this, module, declaringType); + + var td = module.Metadata.GetTypeDefinition(declaringType); + + foreach (var method in td.GetMethods()) { + var parent = method; + var part = method; + + var connectedMethods = new Queue(); + connectedMethods.Enqueue(part); + + while (connectedMethods.Count > 0) { + part = connectedMethods.Dequeue(); + var md = module.Metadata.GetMethodDefinition(part); + + if (!md.HasBody()) { + info.AddMapping(parent, part); + } else { + // TODO : async and yield fsms + + // deal with ldftn instructions, i.e., lambdas + var blob = module.Reader.GetMethodBody(md.RelativeVirtualAddress).GetILReader(); + while (blob.RemainingBytes > 0) { + var code = blob.DecodeOpCode(); + if (code == ILOpCode.Ldftn) { + var token = MetadataTokens.EntityHandle(blob.ReadInt32()); + if (token.Kind == HandleKind.MethodDefinition) { + if (((MethodDefinitionHandle)token).IsCompilerGenerated(module.Metadata)) + connectedMethods.Enqueue((MethodDefinitionHandle)token); + } + } else { + blob.SkipOperand(code); + } + } + + info.AddMapping(parent, part); + } + } + + + } + + return info; + } } class InsertDynamicTypeVisitor : DepthFirstAstVisitor diff --git a/ILSpy/Languages/CodeMappingInfo.cs b/ILSpy/Languages/CodeMappingInfo.cs new file mode 100644 index 000000000..60fba3a36 --- /dev/null +++ b/ILSpy/Languages/CodeMappingInfo.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using System.Threading.Tasks; +using ICSharpCode.Decompiler.Util; + +namespace ICSharpCode.ILSpy +{ + public class CodeMappingInfo + { + public Decompiler.Metadata.PEFile Module { get; } + public Language Language { get; } + public TypeDefinitionHandle TypeDefinition { get; } + + Dictionary> parts; + Dictionary parents; + + public CodeMappingInfo(Language language, Decompiler.Metadata.PEFile module, TypeDefinitionHandle type) + { + this.Language = language; + this.Module = module; + this.TypeDefinition = type; + this.parts = new Dictionary>(); + this.parents = new Dictionary(); + } + + public bool ShowMember(EntityHandle entity) + { + return Language.ShowMember(new Decompiler.Metadata.Entity(Module, entity)); + } + + public IEnumerable GetMethodParts(MethodDefinitionHandle method) + { + if (parts.TryGetValue(method, out var p)) + return p; + return new[] { method }; + } + + public MethodDefinitionHandle GetParentMethod(MethodDefinitionHandle method) + { + if (parents.TryGetValue(method, out var p)) + return p; + return method; + } + + public void AddMapping(MethodDefinitionHandle parent, MethodDefinitionHandle part) + { + Debug.Print("Parent: " + MetadataTokens.GetRowNumber(parent) + " Part: " + MetadataTokens.GetRowNumber(part)); + if (parents.ContainsKey(part)) + return; + parents.Add(part, parent); + if (!parts.TryGetValue(parent, out var list)) { + list = new List(); + parts.Add(parent, list); + } + list.Add(part); + } + } +} diff --git a/ILSpy/Languages/ILSignatureProvider.cs b/ILSpy/Languages/ILSignatureProvider.cs new file mode 100644 index 000000000..3750461e8 --- /dev/null +++ b/ILSpy/Languages/ILSignatureProvider.cs @@ -0,0 +1,172 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Immutable; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Metadata; +using SRM = System.Reflection.Metadata; + +namespace ICSharpCode.ILSpy +{ + class ILSignatureProvider : SRM.ISignatureTypeProvider + { + public static readonly ILSignatureProvider WithoutNamespace = new ILSignatureProvider(false); + public static readonly ILSignatureProvider WithNamespace = new ILSignatureProvider(true); + + bool includeNamespace; + + public ILSignatureProvider(bool includeNamespace) + { + this.includeNamespace = includeNamespace; + } + + public string GetArrayType(string elementType, SRM.ArrayShape shape) + { + string printedShape = ""; + for (int i = 0; i < shape.Rank; i++) { + if (i > 0) + printedShape += ", "; + if (i < shape.LowerBounds.Length || i < shape.Sizes.Length) { + int lower = 0; + if (i < shape.LowerBounds.Length) { + lower = shape.LowerBounds[i]; + printedShape += lower.ToString(); + } + printedShape += "..."; + if (i < shape.Sizes.Length) + printedShape += (lower + shape.Sizes[i] - 1).ToString(); + } + } + return $"{elementType}[{printedShape}]"; + } + + public string GetByReferenceType(string elementType) + { + return elementType + "&"; + } + + public string GetFunctionPointerType(SRM.MethodSignature signature) + { + return "method " + signature.ReturnType + " *(" + string.Join(", ", signature.ParameterTypes) + ")"; + } + + public string GetGenericInstantiation(string genericType, ImmutableArray typeArguments) + { + return genericType + "<" + string.Join(", ", typeArguments) + ">"; + } + + public string GetGenericMethodParameter(GenericContext genericContext, int index) + { + return "!!" + genericContext.GetGenericMethodTypeParameterName(index); + } + + public string GetGenericTypeParameter(GenericContext genericContext, int index) + { + return "!" + genericContext.GetGenericTypeParameterName(index); + } + + public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired) + { + string modifierKeyword = isRequired ? "modreq" : "modopt"; + return $"{unmodifiedType} {modifierKeyword}({modifier})"; + } + + public string GetPinnedType(string elementType) + { + throw new NotImplementedException(); + } + + public string GetPointerType(string elementType) + { + return elementType + "*"; + } + + public string GetPrimitiveType(SRM.PrimitiveTypeCode typeCode) + { + switch (typeCode) { + case SRM.PrimitiveTypeCode.Boolean: + return "bool"; + case SRM.PrimitiveTypeCode.Byte: + return "uint8"; + case SRM.PrimitiveTypeCode.SByte: + return "int8"; + case SRM.PrimitiveTypeCode.Char: + return "char"; + case SRM.PrimitiveTypeCode.Int16: + return "int16"; + case SRM.PrimitiveTypeCode.UInt16: + return "uint16"; + case SRM.PrimitiveTypeCode.Int32: + return "int32"; + case SRM.PrimitiveTypeCode.UInt32: + return "uint32"; + case SRM.PrimitiveTypeCode.Int64: + return "int64"; + case SRM.PrimitiveTypeCode.UInt64: + return "uint64"; + case SRM.PrimitiveTypeCode.Single: + return "float32"; + case SRM.PrimitiveTypeCode.Double: + return "float64"; + case SRM.PrimitiveTypeCode.IntPtr: + return "native int"; + case SRM.PrimitiveTypeCode.UIntPtr: + return "native uint"; + case SRM.PrimitiveTypeCode.Object: + return "object"; + case SRM.PrimitiveTypeCode.String: + return "string"; + case SRM.PrimitiveTypeCode.TypedReference: + return "typedref"; + case SRM.PrimitiveTypeCode.Void: + return "void"; + default: + throw new ArgumentOutOfRangeException(); + } + } + + public string GetSZArrayType(string elementType) + { + return elementType + "[]"; + } + + public string GetTypeFromDefinition(SRM.MetadataReader reader, SRM.TypeDefinitionHandle handle, byte rawTypeKind) + { + if (!includeNamespace) { + return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name); + } + + return handle.GetFullTypeName(reader).ToILNameString(); + } + + public string GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeReferenceHandle handle, byte rawTypeKind) + { + if (!includeNamespace) { + return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name); + } + + return handle.GetFullTypeName(reader).ToILNameString(); + } + + public string GetTypeFromSpecification(SRM.MetadataReader reader, GenericContext genericContext, SRM.TypeSpecificationHandle handle, byte rawTypeKind) + { + return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext); + } + } +} diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 542f5bb67..259c4f252 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -18,7 +18,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Reflection.PortableExecutable; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Util; @@ -270,7 +269,17 @@ namespace ICSharpCode.ILSpy throw new ArgumentNullException(nameof(method)); var metadata = method.Module.Metadata; var md = metadata.GetMethodDefinition(method.Handle); - var name = metadata.GetString(md.Name); + string name; + if (includeTypeName) { + if (includeNamespace) { + name = md.GetDeclaringType().GetFullTypeName(metadata) + "."; + } else { + name = md.GetDeclaringType().GetFullTypeName(metadata).Name + "."; + } + name += metadata.GetString(md.Name); + } else { + name = metadata.GetString(md.Name); + } var signature = md.DecodeSignature(includeNamespace ? ILSignatureProvider.WithNamespace : ILSignatureProvider.WithoutNamespace, new GenericContext(method)); int i = 0; @@ -348,12 +357,18 @@ namespace ICSharpCode.ILSpy return true; } - /// - /// Used by the analyzer to map compiler generated code back to the original code's location - /// - public virtual IMetadataEntity GetOriginalCodeLocation(IMetadataEntity member) + public virtual CodeMappingInfo GetCodeMappingInfo(PEFile module, SRM.EntityHandle member) { - return member; + var parts = new Dictionary(); + var locations = new Dictionary(); + + var declaringType = member.GetDeclaringType(module.Metadata); + + if (declaringType.IsNil && member.Kind == SRM.HandleKind.TypeDefinition) { + declaringType = (SRM.TypeDefinitionHandle)member; + } + + return new CodeMappingInfo(this, module, declaringType); } public static string GetPlatformDisplayName(PEFile module) @@ -382,150 +397,4 @@ namespace ICSharpCode.ILSpy return module.Metadata.MetadataVersion; } } - - class ILSignatureProvider : SRM.ISignatureTypeProvider - { - public static readonly ILSignatureProvider WithoutNamespace = new ILSignatureProvider(false); - public static readonly ILSignatureProvider WithNamespace = new ILSignatureProvider(true); - - bool includeNamespace; - - public ILSignatureProvider(bool includeNamespace) - { - this.includeNamespace = includeNamespace; - } - - public string GetArrayType(string elementType, SRM.ArrayShape shape) - { - string printedShape = ""; - for (int i = 0; i < shape.Rank; i++) { - if (i > 0) - printedShape += ", "; - if (i < shape.LowerBounds.Length || i < shape.Sizes.Length) { - int lower = 0; - if (i < shape.LowerBounds.Length) { - lower = shape.LowerBounds[i]; - printedShape += lower.ToString(); - } - printedShape += "..."; - if (i < shape.Sizes.Length) - printedShape += (lower + shape.Sizes[i] - 1).ToString(); - } - } - return $"{elementType}[{printedShape}]"; - } - - public string GetByReferenceType(string elementType) - { - return elementType + "&"; - } - - public string GetFunctionPointerType(SRM.MethodSignature signature) - { - return "method " + signature.ReturnType + " *(" + string.Join(", ", signature.ParameterTypes) + ")"; - } - - public string GetGenericInstantiation(string genericType, ImmutableArray typeArguments) - { - return genericType + "<" + string.Join(", ", typeArguments) + ">"; - } - - public string GetGenericMethodParameter(GenericContext genericContext, int index) - { - return "!!" + genericContext.GetGenericMethodTypeParameterName(index); - } - - public string GetGenericTypeParameter(GenericContext genericContext, int index) - { - return "!" + genericContext.GetGenericTypeParameterName(index); - } - - public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired) - { - string modifierKeyword = isRequired ? "modreq" : "modopt"; - return $"{unmodifiedType} {modifierKeyword}({modifier})"; - } - - public string GetPinnedType(string elementType) - { - throw new NotImplementedException(); - } - - public string GetPointerType(string elementType) - { - return elementType + "*"; - } - - public string GetPrimitiveType(SRM.PrimitiveTypeCode typeCode) - { - switch (typeCode) { - case SRM.PrimitiveTypeCode.Boolean: - return "bool"; - case SRM.PrimitiveTypeCode.Byte: - return "uint8"; - case SRM.PrimitiveTypeCode.SByte: - return "int8"; - case SRM.PrimitiveTypeCode.Char: - return "char"; - case SRM.PrimitiveTypeCode.Int16: - return "int16"; - case SRM.PrimitiveTypeCode.UInt16: - return "uint16"; - case SRM.PrimitiveTypeCode.Int32: - return "int32"; - case SRM.PrimitiveTypeCode.UInt32: - return "uint32"; - case SRM.PrimitiveTypeCode.Int64: - return "int64"; - case SRM.PrimitiveTypeCode.UInt64: - return "uint64"; - case SRM.PrimitiveTypeCode.Single: - return "float32"; - case SRM.PrimitiveTypeCode.Double: - return "float64"; - case SRM.PrimitiveTypeCode.IntPtr: - return "native int"; - case SRM.PrimitiveTypeCode.UIntPtr: - return "native uint"; - case SRM.PrimitiveTypeCode.Object: - return "object"; - case SRM.PrimitiveTypeCode.String: - return "string"; - case SRM.PrimitiveTypeCode.TypedReference: - return "typedref"; - case SRM.PrimitiveTypeCode.Void: - return "void"; - default: - throw new NotImplementedException(); - } - } - - public string GetSZArrayType(string elementType) - { - return elementType + "[]"; - } - - public string GetTypeFromDefinition(SRM.MetadataReader reader, SRM.TypeDefinitionHandle handle, byte rawTypeKind) - { - if (!includeNamespace) { - return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name); - } - - return handle.GetFullTypeName(reader).ToILNameString(); - } - - public string GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeReferenceHandle handle, byte rawTypeKind) - { - if (!includeNamespace) { - return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name); - } - - return handle.GetFullTypeName(reader).ToILNameString(); - } - - public string GetTypeFromSpecification(SRM.MetadataReader reader, GenericContext genericContext, SRM.TypeSpecificationHandle handle, byte rawTypeKind) - { - return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext); - } - } } diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 1589c47f9..32b272084 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -632,6 +632,17 @@ namespace ICSharpCode.ILSpy } } return null; + case MethodSpecification ms: + resolvedMember = ms.Handle.Resolve(new SimpleMetadataResolveContext(ms.Module)); + if (!resolvedMember.IsNil) { + switch (resolvedMember) { + case MethodDefinition md: + return assemblyListTreeNode.FindMethodNode(md); + default: + throw new NotSupportedException(); + } + } + return null; default: return null; } @@ -655,7 +666,7 @@ namespace ICSharpCode.ILSpy ILSpyTreeNode treeNode = FindTreeNode(reference); if (treeNode != null) { SelectNode(treeNode); - } else if (reference is ICSharpCode.Decompiler.Disassembler.OpCodeInfo opCode) { + } else if (reference is Decompiler.Disassembler.OpCodeInfo opCode) { OpenLink(opCode.Link); } return decompilationTask; diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs index e28593e31..ccab45822 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs @@ -16,8 +16,9 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; using System.Linq; -using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -29,63 +30,107 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (context.TreeView is AnalyzerTreeView && context.SelectedTreeNodes != null && context.SelectedTreeNodes.All(n => n.Parent.IsRoot)) return false; if (context.SelectedTreeNodes == null) - return context.Reference != null && context.Reference.Reference is MemberReference; + return context.Reference != null && IsValidReference(context.Reference.Reference); return context.SelectedTreeNodes.All(n => n is IMemberTreeNode); } public bool IsEnabled(TextViewContext context) { if (context.SelectedTreeNodes == null) - return context.Reference != null && context.Reference.Reference is MemberReference; + return context.Reference != null && context.Reference.Reference is IMetadataEntity; foreach (IMemberTreeNode node in context.SelectedTreeNodes) { - if (!(node.Member is TypeDefinition - || node.Member is FieldDefinition - || node.Member is MethodDefinition - || AnalyzedPropertyTreeNode.CanShow(node.Member) - || AnalyzedEventTreeNode.CanShow(node.Member))) + if (!IsValidReference(node.Member)) return false; } return true; } + bool IsValidReference(object reference) + { + return reference is IMetadataEntity + || reference is MemberReference + || reference is MethodSpecification + || reference is TypeReference + || reference is TypeSpecification; + } + public void Execute(TextViewContext context) { if (context.SelectedTreeNodes != null) { foreach (IMemberTreeNode node in context.SelectedTreeNodes) { Analyze(node.Member); } - } else if (context.Reference != null && context.Reference.Reference is MemberReference) { - if (context.Reference.Reference is MemberReference) - Analyze((MemberReference)context.Reference.Reference); - // TODO: implement support for other references: ParameterReference, etc. + } else if (context.Reference != null && IsValidReference(context.Reference.Reference)) { + Analyze(context.Reference.Reference); } } - public static void Analyze(IMemberReference member) + public static void Analyze(object member) { - var definition = member.GetDefinition(); - if (definition == null) return; - switch (definition) { - case TypeDefinition td: - if (!td.IsNil) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(td)); + switch (member) { + case IMetadataEntity entity: + switch (entity) { + case TypeDefinition td: + if (!td.IsNil) + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(td)); + break; + case FieldDefinition fd: + //if (!fd.IsNil) + // AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd)); + break; + case MethodDefinition md: + if (!md.IsNil) + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md.Module, md.Handle)); + break; + case PropertyDefinition pd: + //if (!pd.IsNil) + // AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedPropertyTreeNode(pd)); + break; + case EventDefinition ed: + //if (!ed.IsNil) + // AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedEventTreeNode(ed)); + break; + default: + throw new NotSupportedException(); + } break; - case FieldDefinition fd: - if (!fd.IsNil) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd)); + case TypeReference tr: + var resolved = tr.Handle.Resolve(new SimpleMetadataResolveContext(tr.Module)); + if (!resolved.IsNil) + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(resolved)); break; - case MethodDefinition md: - if (!md.IsNil) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md)); + case TypeSpecification ts: + resolved = ts.Handle.Resolve(new SimpleMetadataResolveContext(ts.Module)); + if (!resolved.IsNil) + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedTypeTreeNode(resolved)); break; - case PropertyDefinition pd: - if (!pd.IsNil) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedPropertyTreeNode(pd)); + case MemberReference mr: + var resolvedMember = mr.Handle.Resolve(new SimpleMetadataResolveContext(mr.Module)); + if (!resolvedMember.IsNil) { + switch (resolvedMember) { + case FieldDefinition fd: + //AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedFieldTreeNode(fd)); + break; + case MethodDefinition md: + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md.Module, md.Handle)); + break; + default: + throw new NotSupportedException(); + } + } break; - case EventDefinition ed: - if (!ed.IsNil) - AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedEventTreeNode(ed)); + case MethodSpecification ms: + resolvedMember = ms.Handle.Resolve(new SimpleMetadataResolveContext(ms.Module)); + if (!resolvedMember.IsNil) { + switch (resolvedMember) { + case MethodDefinition md: + AnalyzerTreeView.Instance.ShowOrFocus(new AnalyzedMethodTreeNode(md.Module, md.Handle)); + break; + default: + throw new NotSupportedException(); + } + } break; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs index 1dc07921a..1d9cd36d2 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedAssemblyTreeNode.cs @@ -17,7 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; -using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -42,6 +42,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer //this.Children.Add(new AnalyzedAssemblyReferencedByTreeNode(analyzedAssembly)); } - public override IMemberReference Member => null; + public override IMetadataEntity Member => null; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs index 7bfe4a43c..a541e964d 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs @@ -18,39 +18,35 @@ using System; using System.Linq; -using ICSharpCode.Decompiler.Dom; +using System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { internal sealed class AnalyzedEventTreeNode : AnalyzerEntityTreeNode { - private readonly EventDefinition analyzedEvent; - private readonly string prefix; + readonly Decompiler.Metadata.PEFile module; + readonly EventDefinitionHandle analyzedEvent; + readonly string prefix; - public AnalyzedEventTreeNode(EventDefinition analyzedEvent, string prefix = "") + public AnalyzedEventTreeNode(Decompiler.Metadata.PEFile module, EventDefinitionHandle analyzedEvent, string prefix = "") { if (analyzedEvent == null) throw new ArgumentNullException(nameof(analyzedEvent)); + this.module = module; this.analyzedEvent = analyzedEvent; this.prefix = prefix; this.LazyLoading = true; } - public override IMemberReference Member => analyzedEvent; + public override Decompiler.Metadata.IMetadataEntity Member => new Decompiler.Metadata.EventDefinition(module, analyzedEvent); public override object Icon { - get { return EventTreeNode.GetIcon(analyzedEvent); } + get { return EventTreeNode.GetIcon(new Decompiler.Metadata.EventDefinition(module, analyzedEvent)); } } - public override object Text - { - get - { - // TODO: This way of formatting is not suitable for events which explicitly implement interfaces. - return prefix + Language.TypeToString(analyzedEvent.DeclaringType, true) + "." + EventTreeNode.GetText(analyzedEvent, Language); - } - } + // TODO: This way of formatting is not suitable for events which explicitly implement interfaces. + public override object Text => prefix + Language.EventToString(new Decompiler.Metadata.EventDefinition(module, analyzedEvent), includeTypeName: true, includeNamespace: true); protected override void LoadChildren() { @@ -73,7 +69,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer this.Children.Add(new AnalyzedInterfaceEventImplementedByTreeNode(analyzedEvent)); } - public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member) + /*public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member) { if (CanShow(member)) return new AnalyzedEventTreeNode(member as EventDefinition); @@ -88,6 +84,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return !MainWindow.Instance.CurrentLanguage.ShowMember(eventDef.GetAccessors().First().Method) || AnalyzedEventOverridesTreeNode.CanShow(eventDef); - } + }*/ } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs index 4891e8d12..5109d5fc3 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs @@ -20,40 +20,46 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Threading; +using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Disassembler; -using ICSharpCode.Decompiler.Dom; - +using ICSharpCode.Decompiler.TypeSystem; using ILOpCode = System.Reflection.Metadata.ILOpCode; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { - internal sealed class AnalyzedFieldAccessTreeNode : AnalyzerSearchTreeNode + sealed class AnalyzedFieldAccessTreeNode : AnalyzerSearchTreeNode { - private readonly bool showWrites; // true: show writes; false: show read access - private readonly FieldDefinition analyzedField; - private Lazy foundMethods; - private readonly object hashLock = new object(); + readonly bool showWrites; // true: show writes; false: show read access + readonly Decompiler.Metadata.PEFile module; + readonly FieldDefinitionHandle analyzedField; + readonly FullTypeName analyzedTypeName; + readonly string analyzedFieldName; + Lazy> foundMethods; + readonly object hashLock = new object(); - public AnalyzedFieldAccessTreeNode(FieldDefinition analyzedField, bool showWrites) + public AnalyzedFieldAccessTreeNode(Decompiler.Metadata.PEFile module, FieldDefinitionHandle analyzedField, bool showWrites) { if (analyzedField.IsNil) throw new ArgumentNullException(nameof(analyzedField)); + this.module = module; this.analyzedField = analyzedField; + var fd = module.Metadata.GetFieldDefinition(analyzedField); + this.analyzedTypeName = fd.GetDeclaringType().GetFullTypeName(module.Metadata); + this.analyzedFieldName = module.Metadata.GetString(fd.Name); this.showWrites = showWrites; } - public override object Text - { - get { return showWrites ? "Assigned By" : "Read By"; } - } + public override object Text => showWrites ? "Assigned By" : "Read By"; protected override IEnumerable FetchChildren(CancellationToken ct) { - foundMethods = new Lazy(LazyThreadSafetyMode.ExecutionAndPublication); + foundMethods = new Lazy>(LazyThreadSafetyMode.ExecutionAndPublication); - var analyzer = new ScopedWhereUsedAnalyzer(analyzedField, FindReferencesInType); + var analyzer = new ScopedWhereUsedAnalyzer(module, analyzedField, provideTypeSystem: false, FindReferencesInType); foreach (var child in analyzer.PerformAnalysis(ct).OrderBy(n => n.Text)) { yield return child; } @@ -61,35 +67,46 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foundMethods = null; } - private IEnumerable FindReferencesInType(TypeDefinition type) + private IEnumerable FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, IDecompilerTypeSystem typeSystem) { - string name = analyzedField.Name; - - foreach (MethodDefinition method in type.Methods) { + var td = module.Metadata.GetTypeDefinition(type); + foreach (var h in td.GetMethods()) { bool found = false; - if (!method.HasBody) + + var method = module.Metadata.GetMethodDefinition(h); + if (!method.HasBody()) continue; - var blob = method.Body.GetILReader(); - while (blob.RemainingBytes > 0) { - var opCode = ILParser.DecodeOpCode(ref blob); + + var blob = module.Reader.GetMethodBody(method.RelativeVirtualAddress).GetILReader(); + while (!found && blob.RemainingBytes > 0) { + var opCode = blob.DecodeOpCode(); if (!CanBeReference(opCode)) { - ILParser.SkipOperand(ref blob, opCode); + blob.SkipOperand(opCode); continue; } - var field = ILParser.DecodeMemberToken(ref blob, method.Module); - if (field == null || field.Name != name) - continue; - var definition = field.GetDefinition() as FieldDefinition?; - if (definition?.DeclaringType.FullName != analyzedField.DeclaringType.FullName) - continue; - found = true; - break; + var member = MetadataTokens.EntityHandle(blob.ReadInt32()); + switch (member.Kind) { + case HandleKind.FieldDefinition: + // check whether we're looking at the defining assembly + found = member == analyzedField && module == this.module; + break; + case HandleKind.MemberReference: + var mr = module.Metadata.GetMemberReference((MemberReferenceHandle)member); + // safety-check: should always be a field + if (mr.GetKind() != MemberReferenceKind.Field) + break; + if (!module.Metadata.StringComparer.Equals(mr.Name, analyzedFieldName)) + break; + var typeName = mr.Parent.GetFullTypeName(module.Metadata); + found = typeName == analyzedTypeName; + break; + } } if (found) { - MethodDefinition? codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition?; - if (codeLocation != null && !HasAlreadyBeenFound(codeLocation.Value)) { - var node = new AnalyzedMethodTreeNode(codeLocation.Value); + var md = new Decompiler.Metadata.MethodDefinition(module, h); + if (IsNewResult(md)) { + var node = new AnalyzedMethodTreeNode(module, h); node.Language = this.Language; yield return node; } @@ -97,7 +114,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } } - private bool CanBeReference(ILOpCode code) + bool CanBeReference(ILOpCode code) { switch (code) { case ILOpCode.Ldfld: @@ -114,14 +131,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } } - private bool HasAlreadyBeenFound(MethodDefinition method) + bool IsNewResult(Decompiler.Metadata.MethodDefinition method) { - Hashtable hashtable = foundMethods.Value; + var hashtable = foundMethods.Value; lock (hashLock) { if (hashtable.Contains(method)) { return true; } else { - hashtable.Add(method, null); + hashtable.Add(method); return false; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs index a14d51435..f0271e3a2 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs @@ -17,40 +17,37 @@ // DEALINGS IN THE SOFTWARE. using System; -using ICSharpCode.Decompiler.Dom; +using System.Reflection.Metadata; +using ICSharpCode.Decompiler; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { - internal class AnalyzedFieldTreeNode : AnalyzerEntityTreeNode + class AnalyzedFieldTreeNode : AnalyzerEntityTreeNode { - private readonly FieldDefinition analyzedField; + readonly Decompiler.Metadata.PEFile module; + readonly FieldDefinitionHandle analyzedField; - public AnalyzedFieldTreeNode(FieldDefinition analyzedField) + public AnalyzedFieldTreeNode(Decompiler.Metadata.PEFile module, FieldDefinitionHandle analyzedField) { if (analyzedField.IsNil) throw new ArgumentNullException(nameof(analyzedField)); + this.module = module; this.analyzedField = analyzedField; this.LazyLoading = true; } - public override object Icon => FieldTreeNode.GetIcon(analyzedField); + public override object Icon => FieldTreeNode.GetIcon(new Decompiler.Metadata.FieldDefinition(module, analyzedField)); - public override object Text - { - get - { - return Language.TypeToString(analyzedField.DeclaringType, true) + - "." + analyzedField.Name + " : " + this.Language.TypeToString(analyzedField.FieldType, false, analyzedField); - } - } + public override object Text => Language.FieldToString(new Decompiler.Metadata.FieldDefinition(module, analyzedField), true, true); protected override void LoadChildren() { - this.Children.Add(new AnalyzedFieldAccessTreeNode(analyzedField, false)); - if (!analyzedField.IsLiteral) - this.Children.Add(new AnalyzedFieldAccessTreeNode(analyzedField, true)); + this.Children.Add(new AnalyzedFieldAccessTreeNode(module, analyzedField, false)); + var fd = module.Metadata.GetFieldDefinition(analyzedField); + if (!fd.HasFlag(System.Reflection.FieldAttributes.Literal)) + this.Children.Add(new AnalyzedFieldAccessTreeNode(module, analyzedField, true)); } - public override IMemberReference Member => analyzedField; + public override Decompiler.Metadata.IMetadataEntity Member => new Decompiler.Metadata.FieldDefinition(module, analyzedField); } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs index 64e14ca44..ec0def1c6 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Metadata; using System.Threading; using ICSharpCode.Decompiler.TypeSystem; using Mono.Cecil; @@ -27,9 +28,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { internal sealed class AnalyzedInterfaceMethodImplementedByTreeNode : AnalyzerSearchTreeNode { - private readonly MethodDefinition analyzedMethod; + private readonly MethodDefinitionHandle analyzedMethod; - public AnalyzedInterfaceMethodImplementedByTreeNode(MethodDefinition analyzedMethod) + public AnalyzedInterfaceMethodImplementedByTreeNode(MethodDefinitionHandle analyzedMethod) { if (analyzedMethod == null) throw new ArgumentNullException(nameof(analyzedMethod)); diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs index d12c808a3..60765cdca 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs @@ -18,43 +18,37 @@ using System; using System.Reflection; -using ICSharpCode.Decompiler.Dom; +using System.Reflection.Metadata; +using ICSharpCode.Decompiler; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { internal class AnalyzedMethodTreeNode : AnalyzerEntityTreeNode { - private readonly MethodDefinition analyzedMethod; - private readonly string prefix; + readonly Decompiler.Metadata.PEFile module; + readonly MethodDefinitionHandle analyzedMethod; + readonly string prefix; - public AnalyzedMethodTreeNode(MethodDefinition analyzedMethod, string prefix = "") + public AnalyzedMethodTreeNode(Decompiler.Metadata.PEFile module, MethodDefinitionHandle analyzedMethod, string prefix = "") { if (analyzedMethod.IsNil) throw new ArgumentNullException(nameof(analyzedMethod)); + this.module = module; this.analyzedMethod = analyzedMethod; this.prefix = prefix; this.LazyLoading = true; } - public override object Icon - { - get { return MethodTreeNode.GetIcon(analyzedMethod); } - } + public override object Icon => MethodTreeNode.GetIcon(new Decompiler.Metadata.MethodDefinition(module, analyzedMethod)); - public override object Text - { - get - { - return prefix + Language.TypeToString(analyzedMethod.DeclaringType, true) + "." + MethodTreeNode.GetText(analyzedMethod, Language); - } - } + public override object Text => prefix + Language.MethodToString(new Decompiler.Metadata.MethodDefinition(module, analyzedMethod), true, true); protected override void LoadChildren() { - if (analyzedMethod.HasBody) - this.Children.Add(new AnalyzedMethodUsesTreeNode(analyzedMethod)); + if (analyzedMethod.HasBody(module.Metadata)) + this.Children.Add(new AnalyzedMethodUsesTreeNode(module, analyzedMethod)); - if (analyzedMethod.HasFlag(MethodAttributes.Virtual) && !(analyzedMethod.HasFlag(MethodAttributes.NewSlot) && analyzedMethod.HasFlag(MethodAttributes.Final))) + /*if (analyzedMethod.HasFlag(MethodAttributes.Virtual) && !(analyzedMethod.HasFlag(MethodAttributes.NewSlot) && analyzedMethod.HasFlag(MethodAttributes.Final))) this.Children.Add(new AnalyzedVirtualMethodUsedByTreeNode(analyzedMethod)); else this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod)); @@ -63,9 +57,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod)); if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod)) - this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod)); + this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod));*/ } - public override IMemberReference Member => analyzedMethod; + public override Decompiler.Metadata.IMetadataEntity Member => new Decompiler.Metadata.MethodDefinition(module, analyzedMethod); } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs index 5f2b3c9ad..b020ae905 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs @@ -19,10 +19,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Threading; +using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Disassembler; -using ICSharpCode.Decompiler.Dom; using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -31,73 +34,84 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer /// internal sealed class AnalyzedMethodUsesTreeNode : AnalyzerSearchTreeNode { - private readonly MethodDefinition analyzedMethod; + readonly Decompiler.Metadata.PEFile module; + readonly MethodDefinitionHandle analyzedMethod; - public AnalyzedMethodUsesTreeNode(MethodDefinition analyzedMethod) + public AnalyzedMethodUsesTreeNode(Decompiler.Metadata.PEFile module, MethodDefinitionHandle analyzedMethod) { if (analyzedMethod.IsNil) throw new ArgumentNullException(nameof(analyzedMethod)); + this.module = module; this.analyzedMethod = analyzedMethod; } - public override object Text - { - get { return "Uses"; } - } + public override object Text => "Uses"; protected override IEnumerable FetchChildren(CancellationToken ct) { - foreach (var f in GetUsedFields().Distinct()) { - var node = new AnalyzedFieldTreeNode(f); - node.Language = this.Language; - yield return node; - } - foreach (var m in GetUsedMethods().Distinct()) { - var node = new AnalyzedMethodTreeNode(m); - node.Language = this.Language; - yield return node; - } - } - - private IEnumerable GetUsedMethods() - { - if (!analyzedMethod.HasBody) yield break; - var blob = analyzedMethod.Body.GetILReader(); - while (blob.RemainingBytes > 0) { - var opCode = ILParser.DecodeOpCode(ref blob); - switch (opCode.GetOperandType()) { - case OperandType.Method: - case OperandType.Sig: - case OperandType.Tok: - var member = ILParser.DecodeMemberToken(ref blob, analyzedMethod.Module).GetDefinition(); - if (member is MethodDefinition md) - yield return md; - break; - default: - ILParser.SkipOperand(ref blob, opCode); - break; + var mapping = Language.GetCodeMappingInfo(module, analyzedMethod); + foreach (var part in mapping.GetMethodParts(analyzedMethod)) { + foreach (var node in ScanMethod(part)) { + node.Language = this.Language; + yield return node; } } - } - IEnumerable GetUsedFields() - { - if (!analyzedMethod.HasBody) yield break; - var blob = analyzedMethod.Body.GetILReader(); - while (blob.RemainingBytes > 0) { - var opCode = ILParser.DecodeOpCode(ref blob); - switch (opCode.GetOperandType()) { - case OperandType.Field: - case OperandType.Sig: - case OperandType.Tok: - var member = ILParser.DecodeMemberToken(ref blob, analyzedMethod.Module).GetDefinition(); - if (member is FieldDefinition fd) - yield return fd; - break; - default: - ILParser.SkipOperand(ref blob, opCode); - break; + IEnumerable ScanMethod(MethodDefinitionHandle handle) + { + var md = module.Metadata.GetMethodDefinition(handle); + if (!md.HasBody()) yield break; + + var blob = module.Reader.GetMethodBody(md.RelativeVirtualAddress).GetILReader(); + var resolveContext = new SimpleMetadataResolveContext(module); + + while (blob.RemainingBytes > 0) { + var opCode = ILParser.DecodeOpCode(ref blob); + Decompiler.Metadata.MethodDefinition method; + switch (opCode.GetOperandType()) { + case OperandType.Field: + case OperandType.Method: + case OperandType.Sig: + case OperandType.Tok: + var member = MetadataTokens.EntityHandle(blob.ReadInt32()); + switch (member.Kind) { + case HandleKind.FieldDefinition: + if (!Language.ShowMember(new Decompiler.Metadata.TypeDefinition(module, member.GetDeclaringType(module.Metadata))) || !Language.ShowMember(new Decompiler.Metadata.FieldDefinition(module, (FieldDefinitionHandle)member))) break; + yield return new AnalyzedFieldTreeNode(module, (FieldDefinitionHandle)member); + break; + case HandleKind.MethodDefinition: + if (!Language.ShowMember(new Decompiler.Metadata.TypeDefinition(module, member.GetDeclaringType(module.Metadata))) || !Language.ShowMember(new Decompiler.Metadata.MethodDefinition(module, (MethodDefinitionHandle)member))) break; + yield return new AnalyzedMethodTreeNode(module, (MethodDefinitionHandle)member); + break; + case HandleKind.MemberReference: + var mr = module.Metadata.GetMemberReference((MemberReferenceHandle)member); + switch (mr.GetKind()) { + case MemberReferenceKind.Method: + method = MetadataResolver.ResolveAsMethod(member, resolveContext); + if (method.IsNil || !Language.ShowMember(new Decompiler.Metadata.TypeDefinition(method.Module, method.Handle.GetDeclaringType(method.Module.Metadata))) || !Language.ShowMember(method)) break; + yield return new AnalyzedMethodTreeNode(method.Module, method.Handle); + break; + case MemberReferenceKind.Field: + var field = MetadataResolver.ResolveAsField(member, resolveContext); + if (field.IsNil || !Language.ShowMember(new Decompiler.Metadata.TypeDefinition(field.Module, field.Handle.GetDeclaringType(field.Module.Metadata))) || !Language.ShowMember(field)) break; + yield return new AnalyzedFieldTreeNode(field.Module, field.Handle); + break; + default: + throw new ArgumentOutOfRangeException(); + } + break; + case HandleKind.MethodSpecification: + method = MetadataResolver.ResolveAsMethod(member, resolveContext); + if (method.IsNil || !Language.ShowMember(new Decompiler.Metadata.TypeDefinition(method.Module, method.Handle.GetDeclaringType(method.Module.Metadata))) || !Language.ShowMember(method)) break; + yield return new AnalyzedMethodTreeNode(method.Module, method.Handle); + break; + } + break; + default: + ILParser.SkipOperand(ref blob, opCode); + break; + } } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs index 7865c7d48..c70d5439b 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs @@ -16,7 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using ICSharpCode.Decompiler.Dom; +using System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -24,8 +24,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { private readonly string name; - public AnalyzedPropertyAccessorTreeNode(MethodDefinition analyzedMethod, string name) - : base(analyzedMethod) + public AnalyzedPropertyAccessorTreeNode(Decompiler.Metadata.PEFile module, MethodDefinitionHandle analyzedMethod, string name) + : base(module, analyzedMethod) { this.name = name; } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs index 9caaa4b22..c9017371e 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs @@ -17,57 +17,54 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Reflection.Metadata; using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { - internal sealed class AnalyzedPropertyTreeNode : AnalyzerEntityTreeNode + sealed class AnalyzedPropertyTreeNode : AnalyzerEntityTreeNode { - private readonly PropertyDefinition analyzedProperty; - private readonly bool isIndexer; - private readonly string prefix; + readonly Decompiler.Metadata.PEFile module; + readonly PropertyDefinitionHandle analyzedProperty; + readonly bool isIndexer; + readonly string prefix; - public AnalyzedPropertyTreeNode(PropertyDefinition analyzedProperty, string prefix = "") + public AnalyzedPropertyTreeNode(Decompiler.Metadata.PEFile module, PropertyDefinitionHandle analyzedProperty, string prefix = "") { if (analyzedProperty == null) throw new ArgumentNullException(nameof(analyzedProperty)); - this.isIndexer = analyzedProperty.IsIndexer; + using (LoadedAssembly.DisableAssemblyLoad()) { + this.isIndexer = analyzedProperty.HasMatchingDefaultMemberAttribute(module, out _); + } + this.module = module; this.analyzedProperty = analyzedProperty; this.prefix = prefix; this.LazyLoading = true; } - public override object Icon - { - get { return PropertyTreeNode.GetIcon(analyzedProperty, isIndexer); } - } + public override object Icon => PropertyTreeNode.GetIcon(new Decompiler.Metadata.PropertyDefinition(module, analyzedProperty), isIndexer); - public override object Text - { - get - { - // TODO: This way of formatting is not suitable for properties which explicitly implement interfaces. - return prefix + Language.TypeToString(analyzedProperty.DeclaringType, true) + "." + PropertyTreeNode.GetText(analyzedProperty, Language, isIndexer); - } - } + // TODO: This way of formatting is not suitable for properties which explicitly implement interfaces. + public override object Text => prefix + Language.PropertyToString(new Decompiler.Metadata.PropertyDefinition(module, analyzedProperty), includeNamespace: true, includeTypeName: true, isIndexer: isIndexer); protected override void LoadChildren() { - if (!analyzedProperty.GetMethod.IsNil) - this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.GetMethod, "get")); - if (!analyzedProperty.SetMethod.IsNil) - this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.SetMethod, "set")); - foreach (var accessor in analyzedProperty.OtherMethods) - this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null)); + var accessors = module.Metadata.GetPropertyDefinition(analyzedProperty).GetAccessors(); + if (!accessors.Getter.IsNil) + this.Children.Add(new AnalyzedPropertyAccessorTreeNode(module, accessors.Getter, "get")); + if (!accessors.Setter.IsNil) + this.Children.Add(new AnalyzedPropertyAccessorTreeNode(module, accessors.Setter, "set")); + //foreach (var accessor in analyzedProperty.OtherMethods) + // this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null)); - if (AnalyzedPropertyOverridesTreeNode.CanShow(analyzedProperty)) + /*if (AnalyzedPropertyOverridesTreeNode.CanShow(analyzedProperty)) this.Children.Add(new AnalyzedPropertyOverridesTreeNode(analyzedProperty)); if (AnalyzedInterfacePropertyImplementedByTreeNode.CanShow(analyzedProperty)) - this.Children.Add(new AnalyzedInterfacePropertyImplementedByTreeNode(analyzedProperty)); + this.Children.Add(new AnalyzedInterfacePropertyImplementedByTreeNode(analyzedProperty));*/ } - public static AnalyzerTreeNode TryCreateAnalyzer(IMemberReference member) + /*public static AnalyzerTreeNode TryCreateAnalyzer(IMemberReference member) { if (CanShow(member)) return new AnalyzedPropertyTreeNode((PropertyDefinition)member); @@ -82,8 +79,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod.IsNil ? property.SetMethod : property.GetMethod) || AnalyzedPropertyOverridesTreeNode.CanShow(property); - } + }*/ - public override IMemberReference Member => analyzedProperty; + public override Decompiler.Metadata.IMetadataEntity Member => new Decompiler.Metadata.PropertyDefinition(module, analyzedProperty); } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs index ffb6e5bd2..6ebe6dea2 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs @@ -21,13 +21,12 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading; -using ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { internal sealed class AnalyzedTypeExposedByTreeNode : AnalyzerSearchTreeNode { - private readonly TypeDefinition analyzedType; + private readonly Decompiler.Metadata.TypeDefinition analyzedType; public AnalyzedTypeExposedByTreeNode(TypeDefinition analyzedType) { @@ -100,7 +99,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return false; } - private bool TypeIsExposedBy(PropertyDefinition property) + private bool TypeIsExposedBy(Decompiler.Metadata.PropertyDefinition property) { if (IsPrivate(property)) return false; @@ -111,7 +110,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return false; } - private bool TypeIsExposedBy(EventDefinition eventDef) + private bool TypeIsExposedBy(Decompiler.Metadata.EventDefinition eventDef) { if (IsPrivate(eventDef)) return false; @@ -122,7 +121,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return false; } - private bool TypeIsExposedBy(MethodDefinition method) + private bool TypeIsExposedBy(Decompiler.Metadata.MethodDefinition method) { // if the method has overrides, it is probably an explicit interface member // and should be considered part of the public API even though it is marked private. @@ -152,21 +151,21 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return false; } - private static bool IsPrivate(PropertyDefinition property) + private static bool IsPrivate(Decompiler.Metadata.PropertyDefinition property) { bool isGetterPublic = (!property.GetMethod.IsNil && !property.GetMethod.IsPrivate); bool isSetterPublic = (!property.SetMethod.IsNil && !property.SetMethod.IsPrivate); return !(isGetterPublic || isSetterPublic); } - private static bool IsPrivate(EventDefinition eventDef) + private static bool IsPrivate(Decompiler.Metadata.EventDefinition eventDef) { bool isAdderPublic = (eventDef.AddMethod != null && !eventDef.AddMethod.IsPrivate); bool isRemoverPublic = (eventDef.RemoveMethod != null && !eventDef.RemoveMethod.IsPrivate); return !(isAdderPublic || isRemoverPublic); } - public static bool CanShow(TypeDefinition type) + public static bool CanShow(Decompiler.Metadata.TypeDefinition type) { return true; } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs index e69097345..fbcdcea12 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs @@ -20,83 +20,133 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Threading; + +using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Disassembler; -using ICSharpCode.Decompiler.Dom; -using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { - internal sealed class AnalyzedTypeInstantiationsTreeNode : AnalyzerSearchTreeNode + sealed class AnalyzedTypeInstantiationsTreeNode : AnalyzerSearchTreeNode { - private readonly TypeDefinition analyzedType; - private readonly bool isSystemObject; + readonly Decompiler.Metadata.PEFile module; + readonly TypeDefinitionHandle analyzedType; + readonly FullTypeName analyzedTypeName; - public AnalyzedTypeInstantiationsTreeNode(TypeDefinition analyzedType) + public AnalyzedTypeInstantiationsTreeNode(Decompiler.Metadata.PEFile module, TypeDefinitionHandle analyzedType) { if (analyzedType.IsNil) throw new ArgumentNullException(nameof(analyzedType)); + this.module = module; this.analyzedType = analyzedType; - - this.isSystemObject = (analyzedType.FullName.ToString() == "System.Object"); + this.analyzedTypeName = analyzedType.GetFullTypeName(module.Metadata); } - public override object Text - { - get { return "Instantiated By"; } - } + public override object Text => "Instantiated By"; protected override IEnumerable FetchChildren(CancellationToken ct) { - var analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindReferencesInType); + var analyzer = new ScopedWhereUsedAnalyzer(module, analyzedType, provideTypeSystem: false, FindReferencesInType); return analyzer.PerformAnalysis(ct).OrderBy(n => n.Text); } - private IEnumerable FindReferencesInType(TypeDefinition type) + IEnumerable FindReferencesInType(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, IDecompilerTypeSystem typeSystem) { - foreach (MethodDefinition method in type.Methods) { + var td = module.Metadata.GetTypeDefinition(type); + foreach (var h in td.GetMethods()) { bool found = false; - if (!method.HasBody) - continue; - // ignore chained constructors - // (since object is the root of everything, we can short circuit the test in this case) - if (method.IsConstructor && (isSystemObject || analyzedType == type || analyzedType.IsBaseTypeOf(type))) + var method = module.Metadata.GetMethodDefinition(h); + if (!method.HasBody()) continue; - var blob = method.Body.GetILReader(); - + var blob = module.Reader.GetMethodBody(method.RelativeVirtualAddress).GetILReader(); while (!found && blob.RemainingBytes > 0) { - var opCode = ILParser.DecodeOpCode(ref blob); - switch (opCode.GetOperandType()) { - case OperandType.Method: - case OperandType.Sig: - case OperandType.Tok: - var member = ILParser.DecodeMemberToken(ref blob, method.Module); - if (member.Name == ".ctor") { - if (member.DeclaringType.FullName == analyzedType.FullName) { - found = true; - } + var opCode = blob.DecodeOpCode(); + switch (opCode) { + + case ILOpCode.Newobj: + var member = MetadataTokens.EntityHandle(blob.ReadInt32()); + switch (member.Kind) { + case HandleKind.MethodDefinition: + // check whether we're looking at the defining assembly: + if (module != this.module) + break; + var md = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)member); + if (!module.Metadata.StringComparer.Equals(md.Name, ".ctor")) + break; + found = md.GetDeclaringType() == analyzedType; + break; + case HandleKind.MemberReference: + var mr = module.Metadata.GetMemberReference((MemberReferenceHandle)member); + // safety-check: should always be a method + if (mr.GetKind() != MemberReferenceKind.Method) + break; + if (!module.Metadata.StringComparer.Equals(mr.Name, ".ctor")) + break; + switch (mr.Parent.Kind) { + case HandleKind.MethodDefinition: // varargs method + var parentMD = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)mr.Parent); + found = parentMD.GetDeclaringType() == analyzedType; + break; + case HandleKind.ModuleReference: // global function + throw new NotSupportedException(); + default: + var typeName = mr.Parent.GetFullTypeName(module.Metadata); + found = typeName == analyzedTypeName; + break; + } + break; + case HandleKind.MethodSpecification: // do we need to handle these? + throw new NotSupportedException(); + default: + throw new ArgumentOutOfRangeException(); } break; + + case ILOpCode.Initobj: + var referencedType = MetadataTokens.EntityHandle(blob.ReadInt32()); + switch (referencedType.Kind) { + case HandleKind.TypeDefinition: + // check whether we're looking at the defining assembly: + if (module != this.module) + break; + found = referencedType == analyzedType; + break; + case HandleKind.TypeReference: + case HandleKind.TypeSpecification: + var referencedTypeName = referencedType.GetFullTypeName(module.Metadata); + found = referencedTypeName == analyzedTypeName; + break; + default: + throw new ArgumentOutOfRangeException(); + } + break; + default: - ILParser.SkipOperand(ref blob, opCode); + blob.SkipOperand(opCode); break; } } if (found) { - var node = new AnalyzedMethodTreeNode(method); + var node = new AnalyzedMethodTreeNode(module, h); node.Language = this.Language; yield return node; } } } - public static bool CanShow(TypeDefinition type) + public static bool CanShow(MetadataReader metadata, TypeDefinitionHandle handle) { - return (type.IsClass && !(type.HasFlag(TypeAttributes.Abstract) && type.HasFlag(TypeAttributes.Sealed)) && !type.IsEnum); + var td = metadata.GetTypeDefinition(handle); + return (td.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class + && !((td.Attributes & TypeAttributes.Abstract) != 0 && (td.Attributes & TypeAttributes.Sealed) != 0) + && !handle.IsEnum(metadata); } } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs index 7e94f8b1f..c296c75bd 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs @@ -17,53 +17,48 @@ // DEALINGS IN THE SOFTWARE. using System; -using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.Metadata; + +using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { internal class AnalyzedTypeTreeNode : AnalyzerEntityTreeNode { - private readonly TypeDefinition analyzedType; + readonly TypeDefinition analyzedType; + readonly SRM.TypeDefinition td; public AnalyzedTypeTreeNode(TypeDefinition analyzedType) { if (analyzedType.IsNil) throw new ArgumentNullException(nameof(analyzedType)); this.analyzedType = analyzedType; + this.td = analyzedType.Module.Metadata.GetTypeDefinition(analyzedType.Handle); this.LazyLoading = true; } - public override object Icon - { - get { return TypeTreeNode.GetIcon(analyzedType); } - } + public override object Icon => TypeTreeNode.GetIcon(analyzedType); - public override object Text - { - get - { - return Language.TypeToString(analyzedType, true); - } - } + public override object Text => Language.TypeToString(analyzedType, includeNamespace: true); protected override void LoadChildren() { - if (AnalyzedAttributeAppliedToTreeNode.CanShow(analyzedType)) - this.Children.Add(new AnalyzedAttributeAppliedToTreeNode(analyzedType)); - - if (AnalyzedTypeInstantiationsTreeNode.CanShow(analyzedType)) - this.Children.Add(new AnalyzedTypeInstantiationsTreeNode(analyzedType)); - - if (AnalyzedTypeUsedByTreeNode.CanShow(analyzedType)) - this.Children.Add(new AnalyzedTypeUsedByTreeNode(analyzedType)); + //if (AnalyzedAttributeAppliedToTreeNode.CanShow(analyzedType)) + // this.Children.Add(new AnalyzedAttributeAppliedToTreeNode(analyzedType)); - if (AnalyzedTypeExposedByTreeNode.CanShow(analyzedType)) + if (AnalyzedTypeInstantiationsTreeNode.CanShow(analyzedType.Module.Metadata, analyzedType.Handle)) + this.Children.Add(new AnalyzedTypeInstantiationsTreeNode(analyzedType.Module, analyzedType.Handle)); + + if (AnalyzedTypeUsedByTreeNode.CanShow(analyzedType.Module, analyzedType.Handle)) + this.Children.Add(new AnalyzedTypeUsedByTreeNode(analyzedType.Module, analyzedType.Handle)); +/* + if (AnalyzedTypeExposedByTreeNode.CanShow(analyzedType.Module.Metadata, analyzedType.Handle)) this.Children.Add(new AnalyzedTypeExposedByTreeNode(analyzedType)); - if (AnalyzedTypeExtensionMethodsTreeNode.CanShow(analyzedType)) - this.Children.Add(new AnalyzedTypeExtensionMethodsTreeNode(analyzedType)); + if (AnalyzedTypeExtensionMethodsTreeNode.CanShow(analyzedType.Module.Metadata, analyzedType.Handle)) + this.Children.Add(new AnalyzedTypeExtensionMethodsTreeNode(analyzedType));*/ } - public override IMemberReference Member => analyzedType; + public override IMetadataEntity Member => analyzedType; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs index b87d4a3cd..8fb1ccfb0 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedTypeUsedByTreeNode.cs @@ -19,176 +19,221 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Threading; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Disassembler; -using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { internal sealed class AnalyzedTypeUsedByTreeNode : AnalyzerSearchTreeNode { - private readonly TypeDefinition analyzedType; + readonly Decompiler.Metadata.PEFile module; + readonly TypeDefinitionHandle analyzedType; + readonly FullTypeName analyzedTypeName; - public AnalyzedTypeUsedByTreeNode(TypeDefinition analyzedType) + public AnalyzedTypeUsedByTreeNode(Decompiler.Metadata.PEFile module, TypeDefinitionHandle analyzedType) { if (analyzedType.IsNil) throw new ArgumentNullException(nameof(analyzedType)); + this.module = module; this.analyzedType = analyzedType; + this.analyzedTypeName = analyzedType.GetFullTypeName(module.Metadata); } - public override object Text - { - get { return "Used By"; } - } + public override object Text => "Used By"; protected override IEnumerable FetchChildren(CancellationToken ct) { - var analyzer = new ScopedWhereUsedAnalyzer(analyzedType, FindTypeUsage); - return analyzer.PerformAnalysis(ct) - .Cast() - .Where(n => n.Member.DeclaringType.FullName != analyzedType.FullName) - .Distinct(new AnalyzerEntityTreeNodeComparer()) - .OrderBy(n => n.Text); + var analyzer = new ScopedWhereUsedAnalyzer(module, analyzedType, provideTypeSystem: true, FindTypeUsage); + return analyzer.PerformAnalysis(ct).Distinct(AnalyzerEntityTreeNodeComparer.Instance).OrderBy(n => n.Text); } - private IEnumerable FindTypeUsage(TypeDefinition type) + IEnumerable FindTypeUsage(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, IDecompilerTypeSystem typeSystem) { - if (type == analyzedType) + if (type == this.analyzedType && module == this.module) yield break; - if (IsUsedInTypeDefinition(type)) - yield return new AnalyzedTypeTreeNode(type) { Language = Language }; + // TODO : cache / optimize this per assembly + var analyzedTypeDefinition = typeSystem.Compilation.FindType(analyzedTypeName).GetDefinition(); + var typeDefinition = typeSystem.ResolveAsType(type).GetDefinition(); - foreach (var field in type.Fields.Where(IsUsedInField)) - yield return new AnalyzedFieldTreeNode(field) { Language = Language }; + if (analyzedTypeDefinition == null || typeDefinition == null) + yield break; - foreach (var method in type.Methods.Where(IsUsedInMethodDefinition)) - yield return HandleSpecialMethodNode(method); - } + var visitor = new TypeDefinitionUsedVisitor(analyzedTypeDefinition); - private AnalyzerEntityTreeNode HandleSpecialMethodNode(MethodDefinition method) - { - var property = method.DeclaringType.Properties.FirstOrDefault(p => p.GetMethod == method || p.SetMethod == method); - if (property != null) - return new AnalyzedPropertyTreeNode(property) { Language = Language }; + if (typeDefinition.DirectBaseTypes.Any(bt => analyzedTypeDefinition.Equals(bt.GetDefinition()))) + yield return new AnalyzedTypeTreeNode(new Decompiler.Metadata.TypeDefinition(module, type)) { Language = Language }; - return new AnalyzedMethodTreeNode(method) { Language = Language }; - } + foreach (var field in typeDefinition.Fields.Where(f => IsUsedInField(f, visitor))) + yield return new AnalyzedFieldTreeNode(module, (FieldDefinitionHandle)field.MetadataToken) { Language = Language }; - private bool IsUsedInTypeReferences(IEnumerable types) - { - return types.Any(IsUsedInTypeReference); - } + foreach (var method in typeDefinition.Methods.Where(m => IsUsedInMethodDefinition(m, visitor, typeSystem, module))) + yield return new AnalyzedMethodTreeNode(module, (MethodDefinitionHandle)method.MetadataToken) { Language = Language }; - private bool IsUsedInTypeReference(ITypeReference type) - { - if (type == null) - return false; - - return TypeMatches(type.DeclaringType) - || TypeMatches(type); + foreach (var property in typeDefinition.Properties.Where(p => IsUsedInProperty(p, visitor, typeSystem, module))) + yield return new AnalyzedPropertyTreeNode(module, (PropertyDefinitionHandle)property.MetadataToken) { Language = Language }; } - private bool IsUsedInTypeDefinition(TypeDefinition type) + bool IsUsedInField(IField field, TypeDefinitionUsedVisitor visitor) { - return IsUsedInTypeReference(type) - || TypeMatches(type.BaseType) - || IsUsedInTypeReferences(type.Interfaces.Select(i => i.InterfaceType)); + visitor.Found = false; + field.ReturnType.AcceptVisitor(visitor); + return visitor.Found; } - private bool IsUsedInField(FieldDefinition field) + bool IsUsedInProperty(IProperty property, TypeDefinitionUsedVisitor visitor, IDecompilerTypeSystem typeSystem, PEFile module) { - if (field.IsNil) return false; - - return TypeMatches(field.DeclaringType) || field.DecodeSignature(new TypeUsedInSignature(analyzedType), default(Unit)); + visitor.Found = false; + property.ReturnType.AcceptVisitor(visitor); + for (int i = 0; i < property.Parameters.Count && !visitor.Found; i++) + property.Parameters[i].Type.AcceptVisitor(visitor); + return visitor.Found + || (property.CanGet && IsUsedInMethodBody(module, visitor, typeSystem, (MethodDefinitionHandle)property.Getter.MetadataToken)) + || (property.CanSet && IsUsedInMethodBody(module, visitor, typeSystem, (MethodDefinitionHandle)property.Setter.MetadataToken)); } - private bool IsUsedInMethod(MethodDefinition method) + bool IsUsedInMethodDefinition(IMethod method, TypeDefinitionUsedVisitor visitor, IDecompilerTypeSystem typeSystem, PEFile module) { - if (method == null) - return false; - - return TypeMatches(method.DeclaringType) - || TypeMatches(method.ReturnType) - || IsUsedInMethodParameters(method.Parameters); + visitor.Found = false; + method.ReturnType.AcceptVisitor(visitor); + for (int i = 0; i < method.Parameters.Count && !visitor.Found; i++) + method.Parameters[i].Type.AcceptVisitor(visitor); + return visitor.Found || IsUsedInMethodBody(module, visitor, typeSystem, (MethodDefinitionHandle)method.MetadataToken); } - private bool IsUsedInMethodDefinition(MethodDefinition method) + bool IsUsedInMethod(IMethod method, TypeDefinitionUsedVisitor visitor) { - return IsUsedInMethodReference(method) - || IsUsedInMethodBody(method); + visitor.Found = false; + method.ReturnType.AcceptVisitor(visitor); + for (int i = 0; i < method.Parameters.Count && !visitor.Found; i++) + method.Parameters[i].Type.AcceptVisitor(visitor); + return visitor.Found; } - private bool IsUsedInMethodBody(MethodDefinition method) + bool IsUsedInMethodBody(PEFile module, TypeDefinitionUsedVisitor visitor, IDecompilerTypeSystem typeSystem, MethodDefinitionHandle method) { - if (method.Body == null) + if (method.IsNil) + return false; + var md = module.Metadata.GetMethodDefinition(method); + if (!md.HasBody()) return false; - bool found = false; - - foreach (var instruction in method.Body.Instructions) { - TypeReference tr = instruction.Operand as TypeReference; - if (IsUsedInTypeReference(tr)) { - found = true; - break; - } - FieldReference fr = instruction.Operand as FieldReference; - if (IsUsedInFieldReference(fr)) { - found = true; - break; - } - MethodReference mr = instruction.Operand as MethodReference; - if (IsUsedInMethodReference(mr)) { - found = true; - break; + var blob = module.Reader.GetMethodBody(md.RelativeVirtualAddress).GetILReader(); + while (blob.RemainingBytes > 0) { + var opCode = blob.DecodeOpCode(); + switch (opCode.GetOperandType()) { + case OperandType.Field: + case OperandType.Method: + case OperandType.Sig: + case OperandType.Tok: + case OperandType.Type: + var member = MetadataTokens.EntityHandle(blob.ReadInt32()); + switch (member.Kind) { + case HandleKind.TypeReference: + case HandleKind.TypeSpecification: + var resolvedType = typeSystem.ResolveAsType(member); + resolvedType.AcceptVisitor(visitor); + if (visitor.Found) + return true; + break; + + case HandleKind.TypeDefinition: + if (this.module != module) + break; + if (member == analyzedType) + return true; + break; + + case HandleKind.FieldDefinition: + if (this.module != module) + break; + var resolvedField = typeSystem.ResolveAsField(member); + if (IsUsedInField(resolvedField, visitor)) + return true; + break; + + case HandleKind.MethodDefinition: + var resolvedMethod = typeSystem.ResolveAsMethod(member); + if (resolvedMethod == null) + break; + if (IsUsedInMethod(resolvedMethod, visitor)) + return true; + break; + + case HandleKind.MemberReference: + var resolvedMember = typeSystem.ResolveAsMember(member); + if (resolvedMember == null) + break; + if (resolvedMember is IField f && IsUsedInField(f, visitor)) + return true; + if (resolvedMember is IMethod m && IsUsedInMethod(m, visitor)) + return true; + break; + + case HandleKind.MethodSpecification: + resolvedMethod = typeSystem.ResolveAsMethod(member); + if (resolvedMethod == null) + break; + if (IsUsedInMethod(resolvedMethod, visitor)) + return true; + break; + + default: + break; + } + break; + default: + blob.SkipOperand(opCode); + break; } } - method.Body = null; // discard body to reduce memory pressure & higher GC gen collections - - return found; + return false; } - private bool IsUsedInMethodParameters(IEnumerable parameters) + public static bool CanShow(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type) { - return parameters.Any(IsUsedInMethodParameter); + return !type.IsNil; } + } - private bool IsUsedInMethodParameter(ParameterDefinition parameter) - { - return TypeMatches(parameter.ParameterType); - } + class AnalyzerEntityTreeNodeComparer : IEqualityComparer + { + public static readonly AnalyzerEntityTreeNodeComparer Instance = new AnalyzerEntityTreeNodeComparer(); - private bool TypeMatches(ITypeReference tref) + public bool Equals(AnalyzerEntityTreeNode x, AnalyzerEntityTreeNode y) { - if (tref != null && tref.Name == analyzedType.Name) { - var tdef = tref.GetDefinition(); - if (tdef != null) { - return (tdef == analyzedType); - } - } - return false; + return x.Member == y.Member; } - public static bool CanShow(TypeDefinition type) + public int GetHashCode(AnalyzerEntityTreeNode obj) { - return type != null; + return obj.Member.GetHashCode(); } } - internal class AnalyzerEntityTreeNodeComparer : IEqualityComparer + class TypeDefinitionUsedVisitor : TypeVisitor { - public bool Equals(AnalyzerEntityTreeNode x, AnalyzerEntityTreeNode y) + readonly ITypeDefinition typeDefinition; + + public bool Found { get; set; } + + public TypeDefinitionUsedVisitor(ITypeDefinition definition) { - return x.Member == y.Member; + this.typeDefinition = definition; } - public int GetHashCode(AnalyzerEntityTreeNode node) + public override IType VisitTypeDefinition(ITypeDefinition type) { - return node.Member.GetHashCode(); + Found |= typeDefinition.Equals(type); + return base.VisitTypeDefinition(type); } } - } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs index f9df22a2b..d7c0f143d 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzerEntityTreeNode.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.TreeView; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs index 053946bf6..a33d5507e 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzerSearchTreeNode.cs @@ -18,10 +18,7 @@ using System; using System.Collections.Generic; -using System.Reflection.Metadata; using System.Threading; -using ICSharpCode.Decompiler.Disassembler; -using Dom = ICSharpCode.Decompiler.Dom; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { diff --git a/ILSpy/TreeNodes/Analyzer/Extensions.cs b/ILSpy/TreeNodes/Analyzer/Extensions.cs new file mode 100644 index 000000000..c67f062dc --- /dev/null +++ b/ILSpy/TreeNodes/Analyzer/Extensions.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Metadata; +using System.Text; +using System.Threading.Tasks; +using ICSharpCode.Decompiler; + +namespace ICSharpCode.ILSpy.TreeNodes.Analyzer +{ + public static class Extensions + { + public static TypeDefinitionHandle GetDeclaringType(this MethodDefinitionHandle method, MetadataReader metadata) + { + if (method.IsNil) + throw new ArgumentNullException(nameof(method)); + return metadata.GetMethodDefinition(method).GetDeclaringType(); + } + + public static TypeDefinitionHandle GetDeclaringType(this FieldDefinitionHandle field, MetadataReader metadata) + { + if (field.IsNil) + throw new ArgumentNullException(nameof(field)); + return metadata.GetFieldDefinition(field).GetDeclaringType(); + } + + public static TypeDefinitionHandle GetDeclaringType(this PropertyDefinitionHandle property, MetadataReader metadata) + { + if (property.IsNil) + throw new ArgumentNullException(nameof(property)); + var accessor = metadata.GetPropertyDefinition(property).GetAccessors().GetAny(); + return metadata.GetMethodDefinition(accessor).GetDeclaringType(); + } + + public static TypeDefinitionHandle GetDeclaringType(this EventDefinitionHandle @event, MetadataReader metadata) + { + if (@event.IsNil) + throw new ArgumentNullException(nameof(@event)); + var accessor = metadata.GetEventDefinition(@event).GetAccessors().GetAny(); + return metadata.GetMethodDefinition(accessor).GetDeclaringType(); + } + } +} diff --git a/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs b/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs index 7fcca123a..5cdc3a109 100644 --- a/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs +++ b/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs @@ -20,9 +20,10 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Reflection.Metadata; using System.Threading; using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Dom; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.Util; @@ -31,49 +32,57 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer /// /// Determines the accessibility domain of a member for where-used analysis. /// - internal class ScopedWhereUsedAnalyzer + class ScopedWhereUsedAnalyzer { - private readonly PEFile assemblyScope; - private TypeDefinition typeScope; - private static readonly TypeSystemAttributeTypeProvider typeProvider = TypeSystemAttributeTypeProvider.CreateDefault(); + readonly Decompiler.Metadata.PEFile assemblyScope; + readonly bool provideTypeSystem; + TypeDefinitionHandle typeScopeHandle; + TypeDefinition typeScope; + static readonly TypeSystemAttributeTypeProvider typeProvider = TypeSystemAttributeTypeProvider.CreateDefault(); - private readonly Accessibility memberAccessibility = Accessibility.Public; - private Accessibility typeAccessibility = Accessibility.Public; - private readonly Func> typeAnalysisFunction; + readonly Accessibility memberAccessibility = Accessibility.Public; + Accessibility typeAccessibility = Accessibility.Public; + readonly Func> typeAnalysisFunction; - public ScopedWhereUsedAnalyzer(TypeDefinition type, Func> typeAnalysisFunction) + public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, TypeDefinitionHandle type, bool provideTypeSystem, Func> typeAnalysisFunction) { - this.typeScope = type; - this.assemblyScope = type.Module; + this.typeScopeHandle = type; + this.assemblyScope = module; + this.typeScope = module.Metadata.GetTypeDefinition(typeScopeHandle); + this.provideTypeSystem = provideTypeSystem; this.typeAnalysisFunction = typeAnalysisFunction; } - public ScopedWhereUsedAnalyzer(MethodDefinition method, Func> typeAnalysisFunction) - : this(method.DeclaringType, typeAnalysisFunction) + public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, MethodDefinitionHandle method, bool provideTypeSystem, Func> typeAnalysisFunction) + : this(module, method.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction) { - this.memberAccessibility = GetMethodAccessibility(method); + this.memberAccessibility = GetMethodAccessibility(module.Metadata, method); } - public ScopedWhereUsedAnalyzer(PropertyDefinition property, Func> typeAnalysisFunction) - : this(property.DeclaringType, typeAnalysisFunction) + public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, PropertyDefinitionHandle property, bool provideTypeSystem, Func> typeAnalysisFunction) + : this(module, property.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction) { - Accessibility getterAccessibility = (property.GetMethod.IsNil) ? Accessibility.Private : GetMethodAccessibility(property.GetMethod); - Accessibility setterAccessibility = (property.SetMethod.IsNil) ? Accessibility.Private : GetMethodAccessibility(property.SetMethod); + var pd = module.Metadata.GetPropertyDefinition(property); + var accessors = pd.GetAccessors(); + Accessibility getterAccessibility = (accessors.Getter.IsNil) ? Accessibility.Private : GetMethodAccessibility(module.Metadata, accessors.Getter); + Accessibility setterAccessibility = (accessors.Setter.IsNil) ? Accessibility.Private : GetMethodAccessibility(module.Metadata, accessors.Setter); this.memberAccessibility = (Accessibility)Math.Max((int)getterAccessibility, (int)setterAccessibility); } - public ScopedWhereUsedAnalyzer(EventDefinition eventDef, Func> typeAnalysisFunction) - : this(eventDef.DeclaringType, typeAnalysisFunction) + public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, EventDefinitionHandle eventDef, bool provideTypeSystem, Func> typeAnalysisFunction) + : this(module, eventDef.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction) { // we only have to check the accessibility of the the get method // [CLS Rule 30: The accessibility of an event and of its accessors shall be identical.] - this.memberAccessibility = GetMethodAccessibility(eventDef.AddMethod); + var ed = module.Metadata.GetEventDefinition(eventDef); + this.memberAccessibility = GetMethodAccessibility(module.Metadata, ed.GetAccessors().Adder); } - public ScopedWhereUsedAnalyzer(FieldDefinition field, Func> typeAnalysisFunction) - : this(field.DeclaringType, typeAnalysisFunction) + public ScopedWhereUsedAnalyzer(Decompiler.Metadata.PEFile module, FieldDefinitionHandle field, bool provideTypeSystem, Func> typeAnalysisFunction) + : this(module, field.GetDeclaringType(module.Metadata), provideTypeSystem, typeAnalysisFunction) { - switch (field.Attributes & FieldAttributes.FieldAccessMask) { + var fd = module.Metadata.GetFieldDefinition(field); + switch (fd.Attributes & FieldAttributes.FieldAccessMask) { case FieldAttributes.Private: default: memberAccessibility = Accessibility.Private; @@ -96,10 +105,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } } - private Accessibility GetMethodAccessibility(MethodDefinition method) + Accessibility GetMethodAccessibility(MetadataReader metadata, MethodDefinitionHandle method) { Accessibility accessibility; - switch (method.Attributes & MethodAttributes.MemberAccessMask) { + var methodInfo = metadata.GetMethodDefinition(method); + switch (methodInfo.Attributes & MethodAttributes.MemberAccessMask) { case MethodAttributes.Private: default: accessibility = Accessibility.Private; @@ -144,25 +154,26 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return FindReferencesGlobal(ct); } - private void DetermineTypeAccessibility() + void DetermineTypeAccessibility() { - while (!typeScope.DeclaringType.IsNil) { + while (!typeScope.GetDeclaringType().IsNil) { Accessibility accessibility = GetNestedTypeAccessibility(typeScope); if ((int)typeAccessibility > (int)accessibility) { typeAccessibility = accessibility; if (typeAccessibility == Accessibility.Private) return; } - typeScope = typeScope.DeclaringType; + typeScopeHandle = typeScope.GetDeclaringType(); + typeScope = assemblyScope.Metadata.GetTypeDefinition(typeScopeHandle); } - if (typeScope.IsNotPublic && + if ((typeScope.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic && ((int)typeAccessibility > (int)Accessibility.Internal)) { typeAccessibility = Accessibility.Internal; } } - private static Accessibility GetNestedTypeAccessibility(TypeDefinition type) + static Accessibility GetNestedTypeAccessibility(TypeDefinition type) { Accessibility result; switch (type.Attributes & TypeAttributes.VisibilityMask) { @@ -193,7 +204,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer /// /// The effective accessibility of a member /// - private enum Accessibility + enum Accessibility { Private, FamilyAndInternal, @@ -203,7 +214,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer Public } - private IEnumerable FindReferencesInAssemblyAndFriends(CancellationToken ct) + IEnumerable FindReferencesInAssemblyAndFriends(CancellationToken ct) { var assemblies = GetAssemblyAndAnyFriends(assemblyScope, ct); @@ -211,7 +222,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return assemblies.AsParallel().WithCancellation(ct).SelectMany(a => FindReferencesInAssembly(a, ct)); } - private IEnumerable FindReferencesGlobal(CancellationToken ct) + IEnumerable FindReferencesGlobal(CancellationToken ct) { var assemblies = GetReferencingAssemblies(assemblyScope, ct); @@ -219,43 +230,50 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return assemblies.AsParallel().WithCancellation(ct).SelectMany(asm => FindReferencesInAssembly(asm, ct)); } - private IEnumerable FindReferencesInAssembly(PEFile asm, CancellationToken ct) + IEnumerable FindReferencesInAssembly(Decompiler.Metadata.PEFile module, CancellationToken ct) { - foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.TypeDefinitions, t => t.NestedTypes)) { + IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(module) : null; + var metadata = module.Metadata; + foreach (var type in TreeTraversal.PreOrder(metadata.TypeDefinitions, t => metadata.GetTypeDefinition(t).GetNestedTypes())) { ct.ThrowIfCancellationRequested(); - foreach (var result in typeAnalysisFunction(type)) { + foreach (var result in typeAnalysisFunction(module, type, ts)) { ct.ThrowIfCancellationRequested(); yield return result; } } } - private IEnumerable FindReferencesInTypeScope(CancellationToken ct) + IEnumerable FindReferencesInTypeScope(CancellationToken ct) { - foreach (TypeDefinition type in TreeTraversal.PreOrder(typeScope, t => t.NestedTypes)) { + IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope) : null; + foreach (var type in TreeTraversal.PreOrder(typeScopeHandle, t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) { ct.ThrowIfCancellationRequested(); - foreach (var result in typeAnalysisFunction(type)) { + foreach (var result in typeAnalysisFunction(assemblyScope, type, ts)) { ct.ThrowIfCancellationRequested(); yield return result; } } } - private IEnumerable FindReferencesInEnclosingTypeScope(CancellationToken ct) + IEnumerable FindReferencesInEnclosingTypeScope(CancellationToken ct) { - foreach (TypeDefinition type in TreeTraversal.PreOrder(typeScope.DeclaringType, t => t.NestedTypes)) { + IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope) : null; + foreach (var type in TreeTraversal.PreOrder(typeScope.GetDeclaringType(), t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) { ct.ThrowIfCancellationRequested(); - foreach (var result in typeAnalysisFunction(type)) { + foreach (var result in typeAnalysisFunction(assemblyScope, type, ts)) { ct.ThrowIfCancellationRequested(); yield return result; } } } - private IEnumerable GetReferencingAssemblies(PEFile asm, CancellationToken ct) + IEnumerable GetReferencingAssemblies(Decompiler.Metadata.PEFile asm, CancellationToken ct) { yield return asm; + string typeScopeNamespace = asm.Metadata.GetString(typeScope.Namespace); + string typeScopeName = asm.Metadata.GetString(typeScope.Name); + IEnumerable assemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().Where(assy => assy.GetPEFileOrNull()?.IsAssembly == true); foreach (var assembly in assemblies) { @@ -265,7 +283,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer if (module == null) continue; var resolver = assembly.GetAssemblyResolver(); - var metadata = module.GetMetadataReader(); + var metadata = module.Metadata; foreach (var reference in module.AssemblyReferences) { using (LoadedAssembly.DisableAssemblyLoad()) { if (resolver.Resolve(reference) == asm) { @@ -274,17 +292,20 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } } } - if (found && AssemblyReferencesScopeType(module)) + if (found && AssemblyReferencesScopeType(metadata, typeScopeName, typeScopeNamespace)) yield return module; } } - private IEnumerable GetAssemblyAndAnyFriends(PEFile asm, CancellationToken ct) + IEnumerable GetAssemblyAndAnyFriends(Decompiler.Metadata.PEFile asm, CancellationToken ct) { yield return asm; - var reader = asm.GetMetadataReader(); + var metadata = asm.Metadata; + + string typeScopeNamespace = metadata.GetString(typeScope.Namespace); + string typeScopeName = metadata.GetString(typeScope.Name); - var attributes = reader.CustomAttributes.Select(h => reader.GetCustomAttribute(h)).Where(ca => ca.GetAttributeType(asm).FullName.ToString() == "System.Runtime.CompilerServices.InternalsVisibleToAttribute"); + var attributes = metadata.CustomAttributes.Select(h => metadata.GetCustomAttribute(h)).Where(ca => ca.GetAttributeType(metadata).GetFullTypeName(metadata).ToString() == "System.Runtime.CompilerServices.InternalsVisibleToAttribute"); var friendAssemblies = new HashSet(); foreach (var attribute in attributes) { string assemblyName = attribute.DecodeValue(typeProvider).FixedArguments[0].Value as string; @@ -301,18 +322,19 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer var module = assembly.GetPEFileOrNull(); if (module == null) continue; - if (AssemblyReferencesScopeType(module)) + if (AssemblyReferencesScopeType(module.Metadata, typeScopeName, typeScopeNamespace)) yield return module; } } } } - private bool AssemblyReferencesScopeType(PEFile asm) + bool AssemblyReferencesScopeType(MetadataReader metadata, string typeScopeName, string typeScopeNamespace) { bool hasRef = false; - foreach (var typeRef in asm.TypeReferences) { - if (typeRef.Name == typeScope.Name && typeRef.Namespace == typeScope.Namespace) { + foreach (var h in metadata.TypeReferences) { + var typeRef = metadata.GetTypeReference(h); + if (metadata.StringComparer.Equals(typeRef.Name, typeScopeName) && metadata.StringComparer.Equals(typeRef.Namespace, typeScopeNamespace)) { hasRef = true; break; } diff --git a/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs b/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs index 8dcdb730f..e2338966d 100644 --- a/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs +++ b/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs @@ -1,5 +1,6 @@ using System; using System.Windows; +using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.ILSpy.TreeNodes @@ -17,7 +18,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public void Execute(TextViewContext context) { var member = GetMemberNodeFromContext(context)?.Member; - if (member == null) return; + if (member == null || member.IsNil) return; Clipboard.SetText(GetFullyQualifiedName(member)); } @@ -31,14 +32,46 @@ namespace ICSharpCode.ILSpy.TreeNodes /// private string GetFullyQualifiedName(IMetadataEntity member) { - /*if (member.DeclaringType != null) { - if (member is TypeReference) - return GetFullyQualifiedName(member.DeclaringType) + "+" + member.Name; - else - return GetFullyQualifiedName(member.DeclaringType) + "." + member.Name; + string name; + System.Reflection.Metadata.TypeDefinitionHandle declaringType; + switch (member.Handle.Kind) { + case System.Reflection.Metadata.HandleKind.TypeDefinition: + return ((System.Reflection.Metadata.TypeDefinitionHandle)member.Handle).GetFullTypeName(member.Module.Metadata).ToString(); + case System.Reflection.Metadata.HandleKind.FieldDefinition: + name = ""; + declaringType = member.Handle.GetDeclaringType(member.Module.Metadata); + var fd = member.Module.Metadata.GetFieldDefinition((System.Reflection.Metadata.FieldDefinitionHandle)member.Handle); + if (!declaringType.IsNil) { + name = declaringType.GetFullTypeName(member.Module.Metadata) + "."; + } + return name + member.Module.Metadata.GetString(fd.Name); + case System.Reflection.Metadata.HandleKind.MethodDefinition: + name = ""; + declaringType = member.Handle.GetDeclaringType(member.Module.Metadata); + var md = member.Module.Metadata.GetMethodDefinition((System.Reflection.Metadata.MethodDefinitionHandle)member.Handle); + if (!declaringType.IsNil) { + name = declaringType.GetFullTypeName(member.Module.Metadata) + "."; + } + return name + member.Module.Metadata.GetString(md.Name); + case System.Reflection.Metadata.HandleKind.EventDefinition: + name = ""; + declaringType = member.Handle.GetDeclaringType(member.Module.Metadata); + var ed = member.Module.Metadata.GetEventDefinition((System.Reflection.Metadata.EventDefinitionHandle)member.Handle); + if (!declaringType.IsNil) { + name = declaringType.GetFullTypeName(member.Module.Metadata) + "."; + } + return name + member.Module.Metadata.GetString(ed.Name); + case System.Reflection.Metadata.HandleKind.PropertyDefinition: + name = ""; + declaringType = member.Handle.GetDeclaringType(member.Module.Metadata); + var pd = member.Module.Metadata.GetPropertyDefinition((System.Reflection.Metadata.PropertyDefinitionHandle)member.Handle); + if (!declaringType.IsNil) { + name = declaringType.GetFullTypeName(member.Module.Metadata) + "."; + } + return name + member.Module.Metadata.GetString(pd.Name); + default: + throw new ArgumentOutOfRangeException(); } - return (member is TypeReference t ? t.Namespace + "." : "") + member.Name;*/ - throw new NotImplementedException(); } } } \ No newline at end of file diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index 1a96805b1..8ea0910f0 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -30,7 +30,6 @@ namespace ICSharpCode.ILSpy.TreeNodes { public sealed class TypeTreeNode : ILSpyTreeNode, IMemberTreeNode { - readonly TypeDefinition typeDefinition; readonly SRM.TypeDefinition td; public TypeTreeNode(TypeDefinition typeDefinition, AssemblyTreeNode parentAssemblyNode) @@ -38,12 +37,12 @@ namespace ICSharpCode.ILSpy.TreeNodes if (typeDefinition.IsNil) throw new ArgumentNullException(nameof(typeDefinition)); this.ParentAssemblyNode = parentAssemblyNode ?? throw new ArgumentNullException(nameof(parentAssemblyNode)); - this.typeDefinition = typeDefinition; + this.TypeDefinition = typeDefinition; this.td = typeDefinition.Module.Metadata.GetTypeDefinition(typeDefinition.Handle); this.LazyLoading = true; } - public TypeDefinition TypeDefinition => typeDefinition; + public TypeDefinition TypeDefinition { get; } public AssemblyTreeNode ParentAssemblyNode { get; }