Files
RobustToolbox/Robust.Shared/ContentPack/AssemblyTypeChecker.Dump.cs

87 lines
3.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using Internal.TypeSystem.Ecma;
namespace Robust.Shared.ContentPack
{
internal sealed partial class AssemblyTypeChecker
{
public static IEnumerable<(string Value, bool IsField)> DumpMetaMembers(Type type)
{
var assemblyLoc = type.Assembly.Location;
// Load assembly with System.Reflection.Metadata.
using var fs = File.OpenRead(assemblyLoc);
using var peReader = new PEReader(fs);
var metaReader = peReader.GetMetadataReader();
// Find type definition in raw assembly metadata.
// Is there a better way to do this than iterating??
TypeDefinition typeDef = default;
var found = false;
foreach (var typeDefHandle in metaReader.TypeDefinitions)
{
var tempTypeDef = metaReader.GetTypeDefinition(typeDefHandle);
var name = metaReader.GetString(tempTypeDef.Name);
var @namespace = NilNullString(metaReader, tempTypeDef.Namespace);
if (name == type.Name && @namespace == type.Namespace)
{
typeDef = tempTypeDef;
found = true;
break;
}
}
if (!found)
{
throw new InvalidOperationException("Type didn't exist??");
}
// Dump the list.
var provider = new TypeProvider();
foreach (var fieldHandle in typeDef.GetFields())
{
var fieldDef = metaReader.GetFieldDefinition(fieldHandle);
if ((fieldDef.Attributes & FieldAttributes.FieldAccessMask) != FieldAttributes.Public)
{
continue;
}
var fieldName = metaReader.GetString(fieldDef.Name);
var fieldType = fieldDef.DecodeSignature(provider, 0);
yield return ($"{fieldType.WhitelistToString()} {fieldName}", IsField: true);
}
foreach (var methodHandle in typeDef.GetMethods())
{
var methodDef = metaReader.GetMethodDefinition(methodHandle);
if (!methodDef.Attributes.IsPublic())
{
continue;
}
var methodName = metaReader.GetString(methodDef.Name);
var methodSig = methodDef.DecodeSignature(provider, 0);
var paramString = string.Join(", ", methodSig.ParameterTypes.Select(t => t.WhitelistToString()));
var genericCount = methodSig.GenericParameterCount;
var typeParamString = genericCount == 0
? ""
: $"<{new string(',', genericCount - 1)}>";
yield return ($"{methodSig.ReturnType.WhitelistToString()} {methodName}{typeParamString}({paramString})", IsField: false);
}
}
}
}