Created
May 21, 2021 05:26
-
-
Save agocke/6221eaa1b4ad5da3988e98bc1d149a85 to your computer and use it in GitHub Desktop.
Prints signatures of implementations of interfaces in interfaces
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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