From 27cf62d7108bd04a9ab469cdfcf9db47af31a01a Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 13 Jul 2018 11:48:29 +0200 Subject: [PATCH] Move CodeMappingInfo to Decompiler. --- .../CSharp/CSharpDecompiler.cs | 55 +++++++++++++++++++ .../CSharp/RequiredNamespaceCollector.cs | 28 ++++++---- .../ICSharpCode.Decompiler.csproj | 1 + .../Metadata}/CodeMappingInfo.cs | 14 +---- ILSpy/Analyzers/IAnalyzer.cs | 1 + ILSpy/ILSpy.csproj | 1 - ILSpy/Languages/CSharpLanguage.cs | 50 +---------------- ILSpy/Languages/Language.cs | 2 +- 8 files changed, 80 insertions(+), 72 deletions(-) rename {ILSpy/Languages => ICSharpCode.Decompiler/Metadata}/CodeMappingInfo.cs (78%) diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 3f0d4e74e..bf316dab0 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -41,6 +41,8 @@ using ICSharpCode.Decompiler.Metadata; using System.Reflection.PortableExecutable; using ICSharpCode.Decompiler.Documentation; using ICSharpCode.Decompiler.DebugInfo; +using ICSharpCode.Decompiler.Disassembler; +using System.Reflection.Metadata.Ecma335; namespace ICSharpCode.Decompiler.CSharp { @@ -464,6 +466,59 @@ namespace ICSharpCode.Decompiler.CSharp }; } + public static 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(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; + } + /// /// Decompiles the whole module into a single string. /// diff --git a/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs b/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs index 9ccdec117..2360ecdb9 100644 --- a/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs +++ b/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs @@ -34,12 +34,15 @@ namespace ICSharpCode.Decompiler.CSharp HandleAttributes(typeSystem.MainAssembly.GetModuleAttributes(), namespaces); } - public static void CollectNamespaces(IEntity entity, DecompilerTypeSystem typeSystem, HashSet namespaces, bool scanningFullType = false) + public static void CollectNamespaces(IEntity entity, DecompilerTypeSystem typeSystem, + HashSet namespaces, CodeMappingInfo mappingInfo = null, bool scanningFullType = false) { - if (entity == null) + if (entity == null || entity.MetadataToken.IsNil) return; switch (entity) { case ITypeDefinition td: + if (mappingInfo == null) + mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentAssembly.PEFile, entity.MetadataToken); namespaces.Add(td.Namespace); HandleAttributes(td.GetAttributes(), namespaces); @@ -52,23 +55,23 @@ namespace ICSharpCode.Decompiler.CSharp } foreach (var nestedType in td.NestedTypes) { - CollectNamespaces(nestedType, typeSystem, namespaces, scanningFullType: true); + CollectNamespaces(nestedType, typeSystem, namespaces, mappingInfo, scanningFullType: true); } foreach (var field in td.Fields) { - CollectNamespaces(field, typeSystem, namespaces, scanningFullType: true); + CollectNamespaces(field, typeSystem, namespaces, mappingInfo, scanningFullType: true); } foreach (var property in td.Properties) { - CollectNamespaces(property, typeSystem, namespaces, scanningFullType: true); + CollectNamespaces(property, typeSystem, namespaces, mappingInfo, scanningFullType: true); } foreach (var @event in td.Events) { - CollectNamespaces(@event, typeSystem, namespaces, scanningFullType: true); + CollectNamespaces(@event, typeSystem, namespaces, mappingInfo, scanningFullType: true); } foreach (var method in td.Methods) { - CollectNamespaces(method, typeSystem, namespaces, scanningFullType: true); + CollectNamespaces(method, typeSystem, namespaces, mappingInfo, scanningFullType: true); } break; case IField field: @@ -87,10 +90,15 @@ namespace ICSharpCode.Decompiler.CSharp HandleAttributes(typeParam.GetAttributes(), namespaces); } if (!method.MetadataToken.IsNil && method.HasBody) { + if (mappingInfo == null) + mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentAssembly.PEFile, entity.MetadataToken); var reader = typeSystem.ModuleDefinition.Reader; - var methodDef = typeSystem.ModuleDefinition.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); - var body = reader.GetMethodBody(methodDef.RelativeVirtualAddress); - CollectNamespacesFromMethodBody(body, reader, typeSystem, namespaces, scanningFullType: scanningFullType); + var parts = mappingInfo.GetMethodParts((MethodDefinitionHandle)method.MetadataToken).ToList(); + foreach (var part in parts) { + var methodDef = typeSystem.ModuleDefinition.Metadata.GetMethodDefinition(part); + var body = reader.GetMethodBody(methodDef.RelativeVirtualAddress); + CollectNamespacesFromMethodBody(body, reader, typeSystem, namespaces, scanningFullType: scanningFullType); + } } break; case IProperty property: diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 5839f40df..e60af3e58 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -267,6 +267,7 @@ + diff --git a/ILSpy/Languages/CodeMappingInfo.cs b/ICSharpCode.Decompiler/Metadata/CodeMappingInfo.cs similarity index 78% rename from ILSpy/Languages/CodeMappingInfo.cs rename to ICSharpCode.Decompiler/Metadata/CodeMappingInfo.cs index db1a087ea..003c13bde 100644 --- a/ILSpy/Languages/CodeMappingInfo.cs +++ b/ICSharpCode.Decompiler/Metadata/CodeMappingInfo.cs @@ -5,32 +5,24 @@ using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; -namespace ICSharpCode.ILSpy +namespace ICSharpCode.Decompiler.Metadata { public class CodeMappingInfo { - public Decompiler.Metadata.PEFile Module { get; } - public Language Language { get; } + public PEFile Module { get; } public TypeDefinitionHandle TypeDefinition { get; } Dictionary> parts; Dictionary parents; - public CodeMappingInfo(Language language, Decompiler.Metadata.PEFile module, TypeDefinitionHandle type) + public CodeMappingInfo(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) - { - throw null; - //return Language.ShowMember(new Decompiler.Metadata.Entity(Module, entity)); - } - public IEnumerable GetMethodParts(MethodDefinitionHandle method) { if (parts.TryGetValue(method, out var p)) diff --git a/ILSpy/Analyzers/IAnalyzer.cs b/ILSpy/Analyzers/IAnalyzer.cs index 9d052a761..b4e15e0d0 100644 --- a/ILSpy/Analyzers/IAnalyzer.cs +++ b/ILSpy/Analyzers/IAnalyzer.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection.Metadata; using System.Threading; +using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy.Analyzers diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 8896377f1..70e14dbf1 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -130,7 +130,6 @@ DebugSteps.xaml - diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 82bc7643f..d43b39e32 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -564,55 +564,7 @@ namespace ICSharpCode.ILSpy 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; + return CSharpDecompiler.GetCodeMappingInfo(module, member); } } } diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 20d258f99..4ab42a2a6 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -274,7 +274,7 @@ namespace ICSharpCode.ILSpy declaringType = (SRM.TypeDefinitionHandle)member; } - return new CodeMappingInfo(this, module, declaringType); + return new CodeMappingInfo(module, declaringType); } public static string GetPlatformDisplayName(PEFile module)