Skip to content

Instantly share code, notes, and snippets.

@agocke
Created May 21, 2021 05:26
Show Gist options
  • Save agocke/6221eaa1b4ad5da3988e98bc1d149a85 to your computer and use it in GitHub Desktop.
Save agocke/6221eaa1b4ad5da3988e98bc1d149a85 to your computer and use it in GitHub Desktop.
Prints signatures of implementations of interfaces in interfaces
using System;
using System.Collections.Immutable;
using System.IO;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
namespace default_impl
{
class Program
{
static void Main(string[] args)
{
var libpath = Path.Combine(AppContext.BaseDirectory, "testlib.dll");
using var pe = new PEReader(File.OpenRead(libpath));
var mdReader = pe.GetMetadataReader();
foreach (var typeDefHandle in mdReader.TypeDefinitions)
{
if (!typeDefHandle.IsNil)
{
var typeDef = mdReader.GetTypeDefinition(typeDefHandle);
if (typeDef.Attributes.HasFlag(TypeAttributes.Interface))
{
foreach (var implHandle in typeDef.GetMethodImplementations())
{
if (!implHandle.IsNil)
{
var impl = mdReader.GetMethodImplementation(implHandle);
var defOrRef = impl.MethodDeclaration;
if (DumpRec(mdReader, defOrRef) is string s)
{
Console.WriteLine(s);
}
}
}
}
}
}
}
private static string? DumpRec(MetadataReader reader, EntityHandle handle)
{
switch (handle.Kind)
{
case HandleKind.AssemblyReference:
return reader.GetString(reader.GetAssemblyReference((AssemblyReferenceHandle)handle).Name);
case HandleKind.TypeDefinition:
{
TypeDefinition type = reader.GetTypeDefinition((TypeDefinitionHandle)handle);
return getQualifiedName(type.Namespace, type.Name);
}
case HandleKind.MethodDefinition:
{
MethodDefinition method = reader.GetMethodDefinition((MethodDefinitionHandle)handle);
var blob = reader.GetBlobReader(method.Signature);
var decoder = new SignatureDecoder<string, object?>(ConstantSignatureVisualizer.Instance, reader, genericContext: null);
var signature = decoder.DecodeMethodSignature(ref blob);
var parameters = string.Join(", ", signature.ParameterTypes);
return $"{signature.ReturnType} {DumpRec(reader, method.GetDeclaringType())}.{reader.GetString(method.Name)}({parameters})";
}
case HandleKind.MemberReference:
{
MemberReference member = reader.GetMemberReference((MemberReferenceHandle)handle);
var blob = reader.GetBlobReader(member.Signature);
var decoder = new SignatureDecoder<string, object?>(ConstantSignatureVisualizer.Instance, reader, genericContext: null);
var signature = decoder.DecodeMethodSignature(ref blob);
var parameters = string.Join(", ", signature.ParameterTypes);
return $"{signature.ReturnType} {DumpRec(reader, member.Parent)}.{reader.GetString(member.Name)}({parameters})";
}
case HandleKind.TypeReference:
{
TypeReference type = reader.GetTypeReference((TypeReferenceHandle)handle);
return getQualifiedName(type.Namespace, type.Name);
}
case HandleKind.FieldDefinition:
{
FieldDefinition field = reader.GetFieldDefinition((FieldDefinitionHandle)handle);
var name = reader.GetString(field.Name);
var blob = reader.GetBlobReader(field.Signature);
var decoder = new SignatureDecoder<string, object?>(ConstantSignatureVisualizer.Instance, reader, genericContext: null);
var type = decoder.DecodeFieldSignature(ref blob);
return $"{type} {name}";
}
case HandleKind.TypeSpecification:
{
var typeSpec = reader.GetTypeSpecification((TypeSpecificationHandle)handle);
var blob = reader.GetBlobReader(typeSpec.Signature);
var decoder = new SignatureDecoder<string, object?>(ConstantSignatureVisualizer.Instance, reader, genericContext: null);
var type = decoder.DecodeType(ref blob);
return $"{type}";
}
default:
return null;
}
string getQualifiedName(StringHandle leftHandle, StringHandle rightHandle)
{
string name = reader.GetString(rightHandle);
if (!leftHandle.IsNil)
{
name = reader.GetString(leftHandle) + "." + name;
}
return name;
}
}
private sealed class ConstantSignatureVisualizer : ISignatureTypeProvider<string, object?>
{
public static readonly ConstantSignatureVisualizer Instance = new ConstantSignatureVisualizer();
public string GetArrayType(string elementType, ArrayShape shape)
=> elementType + "[" + new string(',', shape.Rank) + "]";
public string GetByReferenceType(string elementType)
=> elementType + "&";
public string GetFunctionPointerType(MethodSignature<string> signature)
=> "method-ptr";
public string GetGenericInstantiation(string genericType, ImmutableArray<string> typeArguments)
=> genericType + "{" + string.Join(", ", typeArguments) + "}";
public string GetGenericMethodParameter(object? genericContext, int index)
=> "!!" + index;
public string GetGenericTypeParameter(object? genericContext, int index)
=> "!" + index;
public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired)
=> (isRequired ? "modreq" : "modopt") + "(" + modifier + ") " + unmodifiedType;
public string GetPinnedType(string elementType)
=> "pinned " + elementType;
public string GetPointerType(string elementType)
=> elementType + "*";
public string GetPrimitiveType(PrimitiveTypeCode typeCode)
=> typeCode.ToString();
public string GetSZArrayType(string elementType)
=> elementType + "[]";
public string GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
{
var typeDef = reader.GetTypeDefinition(handle);
var name = reader.GetString(typeDef.Name);
return typeDef.Namespace.IsNil ? name : reader.GetString(typeDef.Namespace) + "." + name;
}
public string GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
{
var typeRef = reader.GetTypeReference(handle);
var name = reader.GetString(typeRef.Name);
return typeRef.Namespace.IsNil ? name : reader.GetString(typeRef.Namespace) + "." + name;
}
public string GetTypeFromSpecification(MetadataReader reader, object? genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
{
var sigReader = reader.GetBlobReader(reader.GetTypeSpecification(handle).Signature);
return new SignatureDecoder<string, object?>(Instance, reader, genericContext).DecodeType(ref sigReader);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment