Add filenames to Trait/Weapon/SpriteSequence docs metadata.

This commit is contained in:
Paul Chote
2025-01-05 20:01:50 +00:00
committed by Pavel Penev
parent 0efbefc62a
commit 711055a3bc
4 changed files with 57 additions and 0 deletions

View File

@@ -50,6 +50,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
static string GenerateJson(string version, IEnumerable<Type> sequenceTypes)
{
var relatedEnumTypes = new HashSet<Type>();
var pdbReaderCache = Utilities.CreatePdbReaderCache();
var sequenceTypesInfo = sequenceTypes
.Where(x => !x.ContainsGenericParameters && !x.IsAbstract)
@@ -58,6 +59,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
type.Namespace,
type.Name,
Description = string.Join(" ", Utility.GetCustomAttributes<DescAttribute>(type, false).SelectMany(d => d.Lines)),
Filename = Utilities.GetSourceFilenameFromPdb(type, pdbReaderCache),
InheritedTypes = type.BaseTypes()
.Select(y => y.Name)
.Where(y => y != type.Name && y != "Object"),

View File

@@ -48,6 +48,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
static string GenerateJson(string version, IEnumerable<Type> traitTypes, ObjectCreator objectCreator)
{
var relatedEnumTypes = new HashSet<Type>();
var pdbReaderCache = Utilities.CreatePdbReaderCache();
var traitTypesInfo = traitTypes
.Where(x => !x.ContainsGenericParameters && !x.IsAbstract)
@@ -56,6 +57,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
type.Namespace,
Name = type.Name.EndsWith("Info", StringComparison.Ordinal) ? type.Name[..^4] : type.Name,
Description = string.Join(" ", Utility.GetCustomAttributes<DescAttribute>(type, false).SelectMany(d => d.Lines)),
Filename = Utilities.GetSourceFilenameFromPdb(type, pdbReaderCache),
RequiresTraits = RequiredTraitTypes(type)
.Select(y => y.Name),
InheritedTypes = type.BaseTypes()

View File

@@ -53,6 +53,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
static string GenerateJson(string version, IEnumerable<Type> weaponTypes, ObjectCreator objectCreator)
{
var relatedEnumTypes = new HashSet<Type>();
var pdbReaderCache = Utilities.CreatePdbReaderCache();
var weaponTypesInfo = weaponTypes
.Where(x => !x.ContainsGenericParameters && !x.IsAbstract)
@@ -61,6 +62,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
type.Namespace,
Name = type.Name.EndsWith("Info", StringComparison.Ordinal) ? type.Name[..^4] : type.Name,
Description = string.Join(" ", Utility.GetCustomAttributes<DescAttribute>(type, false).SelectMany(d => d.Lines)),
Filename = Utilities.GetSourceFilenameFromPdb(type, pdbReaderCache),
InheritedTypes = type.BaseTypes()
.Select(y => y.Name)
.Where(y => y != type.Name && y != $"{type.Name}Info" && y != "Object"),

View File

@@ -11,7 +11,12 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using OpenRA.FileSystem;
using OpenRA.Primitives;
namespace OpenRA.Mods.Common.UtilityCommands
{
@@ -48,5 +53,51 @@ namespace OpenRA.Mods.Common.UtilityCommands
var topLevelNodes = MiniYaml.Load(fs, manifestNodes, mapProperty);
return topLevelNodes.FirstOrDefault(n => n.Key == key);
}
public static Cache<string, MetadataReader> CreatePdbReaderCache()
{
return new Cache<string, MetadataReader>(assemblyPath =>
{
var pdbPath = Path.ChangeExtension(assemblyPath, "pdb");
using var fs = new FileStream(pdbPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var provider = MetadataReaderProvider.FromPortablePdbStream(fs);
return provider.GetMetadataReader();
});
}
public static string GetSourceFilenameFromPdb(Type type, Cache<string, MetadataReader> pdbReaderCache)
{
var filename = "(unknown)";
try
{
var pdb = pdbReaderCache[type.Assembly.Location];
// Enumerate over ctors before other methods (in case this type is defined across multiple files)
var methodInfos = type.GetConstructors().Cast<MemberInfo>().Concat(type.GetMethods());
foreach (var mi in methodInfos)
{
var definitionHandle = (MethodDefinitionHandle)MetadataTokens.Handle(mi.MetadataToken);
var sequencePoints = pdb.GetMethodDebugInformation(definitionHandle.ToDebugInformationHandle())
.GetSequencePoints()
.ToList();
if (sequencePoints.Count == 0)
continue;
filename = pdb.GetString(pdb.GetDocument(sequencePoints[0].Document).Name);
// Remove the common path prefix to give a path relative to the repository root
for (var i = 0; i < filename.Length; i++)
if (filename[i] != type.Assembly.Location[i])
return filename[i..];
}
}
catch
{
// Ignored
}
return filename;
}
}
}