Browse Source

Further improvements to MetadataResolver and MainWindow.FindTreeNode

pull/1198/head
Siegfried Pammer 7 years ago
parent
commit
1941948a4b
  1. 11
      ICSharpCode.Decompiler/Disassembler/DomExtensions.cs
  2. 1
      ICSharpCode.Decompiler/Metadata/Dom.cs
  3. 26
      ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs
  4. 259
      ICSharpCode.Decompiler/Metadata/MetadataResolver.cs
  5. 23
      ILSpy/MainWindow.xaml.cs

11
ICSharpCode.Decompiler/Disassembler/DomExtensions.cs

@ -84,7 +84,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -84,7 +84,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(' ');
((EntityHandle)fd.GetDeclaringType()).WriteTo(module, output, GenericContext.Empty, ILNameSyntax.TypeName);
output.Write("::");
output.Write(DisassemblerHelpers.Escape(metadata.GetString(fd.Name)));
output.WriteReference(DisassemblerHelpers.Escape(metadata.GetString(fd.Name)), new Metadata.FieldDefinition(module, (FieldDefinitionHandle)entity));
break;
}
case HandleKind.MethodDefinition: {
@ -106,10 +106,11 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -106,10 +106,11 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write("::");
}
bool isCompilerControlled = (md.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope;
var reference = new Metadata.MethodDefinition(module, (MethodDefinitionHandle)entity);
if (isCompilerControlled) {
output.Write(DisassemblerHelpers.Escape(metadata.GetString(md.Name) + "$PST" + MetadataTokens.GetToken(entity).ToString("X8")));
output.WriteReference(DisassemblerHelpers.Escape(metadata.GetString(md.Name) + "$PST" + MetadataTokens.GetToken(entity).ToString("X8")), reference);
} else {
output.Write(DisassemblerHelpers.Escape(metadata.GetString(md.Name)));
output.WriteReference(DisassemblerHelpers.Escape(metadata.GetString(md.Name)), reference);
}
var genericParameters = md.GetGenericParameters();
if (genericParameters.Count > 0) {
@ -173,7 +174,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -173,7 +174,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(' ');
WriteParent(output, module, metadata, mr.Parent, genericContext, syntax);
output.Write("::");
output.Write(DisassemblerHelpers.Escape(memberName));
output.WriteReference(DisassemblerHelpers.Escape(memberName), new Metadata.MemberReference(module, (MemberReferenceHandle)entity));
output.Write("(");
for (int i = 0; i < methodSignature.ParameterTypes.Length; ++i) {
if (i > 0)
@ -190,7 +191,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -190,7 +191,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(' ');
WriteParent(output, module, metadata, mr.Parent, genericContext, syntax);
output.Write("::");
output.Write(DisassemblerHelpers.Escape(memberName));
output.WriteReference(DisassemblerHelpers.Escape(memberName), new Metadata.MemberReference(module, (MemberReferenceHandle)entity));
break;
}
break;

1
ICSharpCode.Decompiler/Metadata/Dom.cs

@ -68,6 +68,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -68,6 +68,7 @@ namespace ICSharpCode.Decompiler.Metadata
{
PEFile Module { get; }
EntityHandle Handle { get; }
bool IsNil { get; }
}
public struct Variable

26
ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs

@ -18,32 +18,6 @@ namespace ICSharpCode.Decompiler.Metadata @@ -18,32 +18,6 @@ namespace ICSharpCode.Decompiler.Metadata
{
public static class MetadataExtensions
{
#region Resolver
public static TypeDefinition ResolveAsType(this EntityHandle entity, PEFile module)
{
return new Entity(module, entity).ResolveAsType();
}
public static FieldDefinition ResolveAsField(this EntityHandle entity, PEFile module)
{
return new Entity(module, entity).ResolveAsField();
}
public static MethodDefinition ResolveAsMethod(this EntityHandle entity, PEFile module)
{
return new Entity(module, entity).ResolveAsMethod();
}
#endregion
public static MethodDefinition AsMethod(this IMetadataEntity entity)
{
if (entity is MethodDefinition method)
return method;
if (entity is Entity e)
return e;
throw new NotSupportedException();
}
public static bool IsNil(this IAssemblyReference reference)
{
return reference == null || (reference is Metadata.AssemblyReference ar && ar.IsNil);

259
ICSharpCode.Decompiler/Metadata/MetadataResolver.cs

@ -8,6 +8,7 @@ using System.Reflection.PortableExecutable; @@ -8,6 +8,7 @@ using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.Util;
using SRM = System.Reflection.Metadata;
namespace ICSharpCode.Decompiler.Metadata
{
@ -21,12 +22,20 @@ namespace ICSharpCode.Decompiler.Metadata @@ -21,12 +22,20 @@ namespace ICSharpCode.Decompiler.Metadata
{
readonly PEFile mainModule;
readonly IAssemblyResolver assemblyResolver;
readonly Dictionary<IAssemblyReference, PEFile> loadedModules = new Dictionary<IAssemblyReference, PEFile>();
readonly Dictionary<IAssemblyReference, PEFile> loadedModules;
public SimpleMetadataResolveContext(PEFile mainModule)
{
this.mainModule = mainModule;
this.assemblyResolver = mainModule.AssemblyResolver;
this.loadedModules = new Dictionary<IAssemblyReference, PEFile>();
}
public SimpleMetadataResolveContext(PEFile mainModule, IMetadataResolveContext parentContext)
{
this.mainModule = mainModule;
this.assemblyResolver = mainModule.AssemblyResolver;
this.loadedModules = parentContext is SimpleMetadataResolveContext simple ? simple.loadedModules : new Dictionary<IAssemblyReference, PEFile>();
}
public PEFile CurrentModule => mainModule;
@ -63,12 +72,10 @@ namespace ICSharpCode.Decompiler.Metadata @@ -63,12 +72,10 @@ namespace ICSharpCode.Decompiler.Metadata
case HandleKind.MethodDefinition:
return new MethodDefinition(context.CurrentModule, (MethodDefinitionHandle)handle);
case HandleKind.MemberReference:
var memberRefHandle = (MemberReferenceHandle)handle;
var metadata = context.CurrentModule.Metadata;
var memberRef = metadata.GetMemberReference(memberRefHandle);
if (memberRef.GetKind() != MemberReferenceKind.Method)
return default;
break;
var resolved = ((MemberReferenceHandle)handle).Resolve(context);
if (resolved is MethodDefinition m)
return m;
return default;
}
throw new NotImplementedException();
}
@ -79,13 +86,10 @@ namespace ICSharpCode.Decompiler.Metadata @@ -79,13 +86,10 @@ namespace ICSharpCode.Decompiler.Metadata
case HandleKind.FieldDefinition:
return new FieldDefinition(context.CurrentModule, (FieldDefinitionHandle)handle);
case HandleKind.MemberReference:
var memberRefHandle = (MemberReferenceHandle)handle;
var metadata = context.CurrentModule.Metadata;
var memberRef = metadata.GetMemberReference(memberRefHandle);
if (memberRef.GetKind() != MemberReferenceKind.Field)
throw new ArgumentException("MemberReferenceKind must be Field!", nameof(handle));
break;
var resolved = ((MemberReferenceHandle)handle).Resolve(context);
if (resolved is FieldDefinition m)
return m;
return default;
}
throw new NotImplementedException();
}
@ -169,46 +173,65 @@ namespace ICSharpCode.Decompiler.Metadata @@ -169,46 +173,65 @@ namespace ICSharpCode.Decompiler.Metadata
return default;
}
public static IMetadataEntity Resolve(MemberReferenceHandle handle, IMetadataResolveContext context)
public static IMetadataEntity Resolve(this MemberReferenceHandle handle, IMetadataResolveContext context)
{
var metadata = context.CurrentModule.Metadata;
var mr = metadata.GetMemberReference(handle);
TypeDefinition declaringType;
SRM.TypeDefinition declaringType;
MetadataReader targetMetadata;
PEFile targetModule;
switch (mr.Parent.Kind) {
case HandleKind.TypeDefinition:
declaringType = new TypeDefinition(context.CurrentModule, (TypeDefinitionHandle)mr.Parent);
declaringType = metadata.GetTypeDefinition((TypeDefinitionHandle)mr.Parent);
targetMetadata = metadata;
targetModule = context.CurrentModule;
break;
case HandleKind.TypeReference:
declaringType = Resolve((TypeReferenceHandle)mr.Parent, context);
var resolvedTypeReference = Resolve((TypeReferenceHandle)mr.Parent, context);
targetModule = resolvedTypeReference.Module;
targetMetadata = targetModule.Metadata;
declaringType = targetMetadata.GetTypeDefinition(resolvedTypeReference.Handle);
break;
case HandleKind.TypeSpecification:
resolvedTypeReference = Resolve((TypeSpecificationHandle)mr.Parent, context);
targetModule = resolvedTypeReference.Module;
targetMetadata = targetModule.Metadata;
declaringType = targetMetadata.GetTypeDefinition(resolvedTypeReference.Handle);
break;
case HandleKind.MethodDefinition:
case HandleKind.ModuleReference:
throw new NotImplementedException();
default:
throw new NotSupportedException();
}
/*var name = metadata.GetString(mr.Name);
var name = metadata.GetString(mr.Name);
switch (mr.GetKind()) {
case MemberReferenceKind.Field:
return declaringType.Fields.FirstOrDefault(fd => fd.Name == name);
foreach (var f in declaringType.GetFields()) {
var fd = targetMetadata.GetFieldDefinition(f);
if (targetMetadata.StringComparer.Equals(fd.Name, name))
return new FieldDefinition(targetModule, f);
}
throw new NotSupportedException();
case MemberReferenceKind.Method:
var signature = mr.DecodeMethodSignature(new TypeSystem.Implementation.TypeReferenceSignatureDecoder(), default(Unit));
return declaringType.Methods.SingleOrDefault(md => MatchMethodDefinition(name, signature, md));
}*/
var candidates = new List<(MethodDefinitionHandle, BlobHandle)>();
foreach (var m in declaringType.GetMethods()) {
var md = targetMetadata.GetMethodDefinition(m);
if (targetMetadata.StringComparer.Equals(md.Name, name))
candidates.Add((m, md.Signature));
}
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))
return new MethodDefinition(targetModule, method);
}
throw new NotSupportedException();
}
throw new NotSupportedException();
}
static bool MatchMethodDefinition(string name, MethodSignature<TypeSystem.ITypeReference> signature, MethodDefinition md)
{
throw new NotImplementedException();
//if (name != md.Name || md.GenericParameters.Count != signature.GenericParameterCount || signature.RequiredParameterCount != md.Parameters.Count)
// return false;
// TODO overload resolution... OMG
//return true;
}
public static TypeDefinition Resolve(TypeSpecificationHandle handle, IMetadataResolveContext context)
public static TypeDefinition Resolve(this TypeSpecificationHandle handle, IMetadataResolveContext context)
{
var metadata = context.CurrentModule.Metadata;
var ts = metadata.GetTypeSpecification(handle);
@ -297,11 +320,175 @@ namespace ICSharpCode.Decompiler.Metadata @@ -297,11 +320,175 @@ namespace ICSharpCode.Decompiler.Metadata
}
}
public struct SignatureBlobComparer
public static class SignatureBlobComparer
{
public bool Compare(BlobHandle a, BlobHandle b)
public static bool EqualsMethodSignature(BlobReader a, BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB)
{
return EqualsMethodSignature(ref a, ref b, contextForA, contextForB);
}
static bool EqualsMethodSignature(ref BlobReader a, ref BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB)
{
SignatureHeader header;
// compare signature headers
if (a.RemainingBytes == 0 || b.RemainingBytes == 0 || (header = a.ReadSignatureHeader()) != b.ReadSignatureHeader())
return false;
if (header.IsGeneric) {
// read & compare generic parameter count
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
}
// read & compare parameter count
if (!IsSameCompressedInteger(ref a, ref b, out int totalParameterCount))
return false;
if (!IsSameCompressedInteger(ref a, ref b, out int typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
int i = 0;
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))
return false;
}
for (; i < totalParameterCount; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
}
return true;
}
static bool IsSameCompressedInteger(ref BlobReader a, ref BlobReader b, out int value)
{
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;
}
static bool TypesAreEqual(ref BlobReader a, ref BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext 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
return true;
case 15: // pointer type
case 16: // byref type
case 69: // pinned type
case 29: // szarray type
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:
if (!EqualsMethodSignature(ref a, ref b, contextForA, contextForB))
return false;
return true;
case 20: // array type
// element type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
// rank
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
// sizes
if (!IsSameCompressedInteger(ref a, ref b, out int numOfSizes))
return false;
for (int i = 0; i < numOfSizes; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
}
// lowerBounds
if (!IsSameCompressedInteger(ref a, ref b, out int numOfLowerBounds))
return false;
for (int i = 0; i < numOfLowerBounds; i++) {
if (!IsSameCompressedSignedInteger(ref a, ref b, out _))
return false;
}
return true;
case 31: // mod-req type
case 32: // mod-opt type
// modifier
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB))
return false;
// unmodified type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
return true;
case 21: // generic instance type
// generic type
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
if (!IsSameCompressedInteger(ref a, ref b, out int numOfArguments))
return false;
for (int i = 0; i < numOfArguments; i++) {
if (!IsSameCompressedInteger(ref a, ref b, out typeCode))
return false;
if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode))
return false;
}
return true;
case 19: // type parameter
case 30: // method type parameter
// index
if (!IsSameCompressedInteger(ref a, ref b, out _))
return false;
return true;
case 17:
case 18:
if (!TypeHandleEquals(ref a, ref b, contextForA, contextForB))
return false;
return true;
default:
return false;
}
}
static bool TypeHandleEquals(ref BlobReader a, ref BlobReader b, IMetadataResolveContext contextForA, IMetadataResolveContext contextForB)
{
return false;
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;
}
}
}

23
ILSpy/MainWindow.xaml.cs

@ -609,6 +609,29 @@ namespace ICSharpCode.ILSpy @@ -609,6 +609,29 @@ namespace ICSharpCode.ILSpy
default:
throw new NotSupportedException();
}
case TypeReference tr:
var resolved = tr.Handle.Resolve(new SimpleMetadataResolveContext(tr.Module));
if (!resolved.IsNil)
return assemblyListTreeNode.FindTypeNode(resolved);
return null;
case TypeSpecification ts:
resolved = ts.Handle.Resolve(new SimpleMetadataResolveContext(ts.Module));
if (!resolved.IsNil)
return assemblyListTreeNode.FindTypeNode(resolved);
return null;
case MemberReference mr:
var resolvedMember = mr.Handle.Resolve(new SimpleMetadataResolveContext(mr.Module));
if (!resolvedMember.IsNil) {
switch (resolvedMember) {
case FieldDefinition fd:
return assemblyListTreeNode.FindFieldNode(fd);
case MethodDefinition md:
return assemblyListTreeNode.FindMethodNode(md);
default:
throw new NotSupportedException();
}
}
return null;
default:
return null;
}

Loading…
Cancel
Save