mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
Adds the generic MetadataTableTreeNode<TEntry> base — caches LoadTable's result and runs it through MetadataTextWriter for the Phase 1 text dump. Ports Module / TypeRef / TypeDef / AssemblyRef as the first concrete leaves; the remaining 31 CorTables and 8 DebugTables continue to land through the universal placeholder until subsequent commits replace them. Also fixes MetadataTextWriter to convert enum values to their underlying integer before applying digit-bearing format strings, since Enum.ToString rejects "X8". Assisted-by: Claude:claude-opus-4-7:Claude Codepull/3755/head
8 changed files with 520 additions and 4 deletions
@ -0,0 +1,130 @@
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System.Linq; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
using System.Threading.Tasks; |
||||
|
||||
using Avalonia.Headless.NUnit; |
||||
|
||||
using AwesomeAssertions; |
||||
|
||||
using ILSpy.AppEnv; |
||||
using ILSpy.Metadata; |
||||
using ILSpy.Metadata.CorTables; |
||||
using ILSpy.TreeNodes; |
||||
using ILSpy.ViewModels; |
||||
using ILSpy.Views; |
||||
|
||||
using NUnit.Framework; |
||||
|
||||
namespace ICSharpCode.ILSpy.Tests.Metadata; |
||||
|
||||
[TestFixture] |
||||
public class TypedMetadataTableTreeTests |
||||
{ |
||||
[AvaloniaTest] |
||||
public async Task AssemblyRefTableTreeNode_Decompiles_To_A_Row_Per_AssemblyReference() |
||||
{ |
||||
// CoreLib's AssemblyRef table holds the assemblies it depends on (typically a
|
||||
// handful: System.Runtime, System.Threading, …). Selecting the typed table node
|
||||
// should render one row per reference with the reference's display name visible.
|
||||
|
||||
var window = AppComposition.Current.GetExport<MainWindow>(); |
||||
window.Show(); |
||||
var vm = (MainWindowViewModel)window.DataContext!; |
||||
// CoreLib has zero AssemblyRefs (it's the bottom of the dep chain), so target
|
||||
// System.Linq instead — same approach as the broader assembly-tree tests.
|
||||
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3); |
||||
|
||||
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq"); |
||||
assemblyNode.EnsureLazyChildren(); |
||||
var metadataNode = assemblyNode.Children.OfType<MetadataTreeNode>().Single(); |
||||
metadataNode.EnsureLazyChildren(); |
||||
var tablesNode = metadataNode.Children.OfType<MetadataTablesTreeNode>().Single(); |
||||
tablesNode.EnsureLazyChildren(); |
||||
var assemblyRefNode = tablesNode.Children.OfType<AssemblyRefTableTreeNode>().Single(); |
||||
|
||||
assemblyRefNode.Kind.Should().Be(TableIndex.AssemblyRef); |
||||
assemblyRefNode.RowCount.Should().BeGreaterThan(0); |
||||
|
||||
vm.AssemblyTreeModel.SelectNode(assemblyRefNode); |
||||
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync(); |
||||
|
||||
tab.Text.Should().Contain("AssemblyRef"); |
||||
tab.Text.Should().Contain("Name"); |
||||
tab.Text.Should().Contain("Version"); |
||||
// CoreLib references almost always include System.Runtime or netstandard.
|
||||
tab.Text.Should().MatchRegex(@"\b(System\.Runtime|netstandard|System\.Private\.CoreLib|System\.Threading)\b"); |
||||
} |
||||
|
||||
[AvaloniaTest] |
||||
public async Task TypeDefTableTreeNode_Decompiles_To_A_Row_Per_Type_Definition() |
||||
{ |
||||
var window = AppComposition.Current.GetExport<MainWindow>(); |
||||
window.Show(); |
||||
var vm = (MainWindowViewModel)window.DataContext!; |
||||
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1); |
||||
|
||||
var coreLibName = typeof(object).Assembly.GetName().Name!; |
||||
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>(coreLibName); |
||||
assemblyNode.EnsureLazyChildren(); |
||||
var metadataNode = assemblyNode.Children.OfType<MetadataTreeNode>().Single(); |
||||
metadataNode.EnsureLazyChildren(); |
||||
var tablesNode = metadataNode.Children.OfType<MetadataTablesTreeNode>().Single(); |
||||
tablesNode.EnsureLazyChildren(); |
||||
var typeDefNode = tablesNode.Children.OfType<TypeDefTableTreeNode>().Single(); |
||||
|
||||
typeDefNode.Kind.Should().Be(TableIndex.TypeDef); |
||||
// CoreLib has thousands of type definitions.
|
||||
typeDefNode.RowCount.Should().BeGreaterThan(1000); |
||||
|
||||
vm.AssemblyTreeModel.SelectNode(typeDefNode); |
||||
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync(); |
||||
|
||||
tab.Text.Should().Contain("TypeDef"); |
||||
// Object is the very first entry every CLI assembly produces (after <Module>).
|
||||
tab.Text.Should().Contain("Object"); |
||||
} |
||||
|
||||
[AvaloniaTest] |
||||
public async Task ModuleTableTreeNode_Decompiles_To_A_Single_Row_Carrying_The_Module_Name() |
||||
{ |
||||
var window = AppComposition.Current.GetExport<MainWindow>(); |
||||
window.Show(); |
||||
var vm = (MainWindowViewModel)window.DataContext!; |
||||
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1); |
||||
|
||||
var coreLibName = typeof(object).Assembly.GetName().Name!; |
||||
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>(coreLibName); |
||||
assemblyNode.EnsureLazyChildren(); |
||||
var metadataNode = assemblyNode.Children.OfType<MetadataTreeNode>().Single(); |
||||
metadataNode.EnsureLazyChildren(); |
||||
var tablesNode = metadataNode.Children.OfType<MetadataTablesTreeNode>().Single(); |
||||
tablesNode.EnsureLazyChildren(); |
||||
var moduleNode = tablesNode.Children.OfType<ModuleTableTreeNode>().Single(); |
||||
|
||||
moduleNode.RowCount.Should().Be(1, "Module is a one-row table by spec"); |
||||
|
||||
vm.AssemblyTreeModel.SelectNode(moduleNode); |
||||
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync(); |
||||
|
||||
tab.Text.Should().Contain("Module"); |
||||
tab.Text.Should().Contain(".dll"); |
||||
} |
||||
} |
||||
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Reflection; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the AssemblyRef table — every external assembly the module imports. Each row
|
||||
/// carries the reference's name, version, culture, and the public-key-or-token blob
|
||||
/// that pins it to a specific signing identity.
|
||||
/// </summary>
|
||||
public sealed class AssemblyRefTableTreeNode : MetadataTableTreeNode<AssemblyRefTableTreeNode.AssemblyRefEntry> |
||||
{ |
||||
public AssemblyRefTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.AssemblyRef, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<AssemblyRefEntry> LoadTable() |
||||
{ |
||||
var list = new List<AssemblyRefEntry>(); |
||||
foreach (var row in metadataFile.Metadata.AssemblyReferences) |
||||
list.Add(new AssemblyRefEntry(metadataFile, row)); |
||||
return list; |
||||
} |
||||
|
||||
public sealed class AssemblyRefEntry |
||||
{ |
||||
readonly MetadataFile metadataFile; |
||||
readonly AssemblyReferenceHandle handle; |
||||
readonly System.Reflection.Metadata.AssemblyReference assemblyRef; |
||||
|
||||
public int RID => MetadataTokens.GetRowNumber(handle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => MetadataTokens.GetToken(handle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Offset => metadataFile.MetadataOffset |
||||
+ metadataFile.Metadata.GetTableMetadataOffset(TableIndex.AssemblyRef) |
||||
+ metadataFile.Metadata.GetTableRowSize(TableIndex.AssemblyRef) * (RID - 1); |
||||
|
||||
public Version Version => assemblyRef.Version; |
||||
|
||||
[ColumnInfo("X8")] |
||||
public AssemblyFlags Flags => assemblyRef.Flags; |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.HeapOffset)] |
||||
public int PublicKeyOrToken => MetadataTokens.GetHeapOffset(assemblyRef.PublicKeyOrToken); |
||||
|
||||
public string Name => metadataFile.Metadata.GetString(assemblyRef.Name); |
||||
|
||||
public string Culture => metadataFile.Metadata.GetString(assemblyRef.Culture); |
||||
|
||||
public AssemblyRefEntry(MetadataFile metadataFile, AssemblyReferenceHandle handle) |
||||
{ |
||||
this.metadataFile = metadataFile; |
||||
this.handle = handle; |
||||
assemblyRef = metadataFile.Metadata.GetAssemblyReference(handle); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,79 @@
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the Module table — always exactly one row carrying the module name and the
|
||||
/// MVID (the GUID identifying this module's identity). Reads the GUID heap for MVID and
|
||||
/// the optional generation IDs (only present in EnC / hot-reload deltas).
|
||||
/// </summary>
|
||||
public sealed class ModuleTableTreeNode : MetadataTableTreeNode<ModuleTableTreeNode.ModuleEntry> |
||||
{ |
||||
public ModuleTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.Module, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<ModuleEntry> LoadTable() |
||||
=> [new ModuleEntry(metadataFile, (ModuleDefinitionHandle)EntityHandle.ModuleDefinition)]; |
||||
|
||||
public sealed class ModuleEntry |
||||
{ |
||||
readonly MetadataFile metadataFile; |
||||
readonly ModuleDefinitionHandle handle; |
||||
readonly ModuleDefinition moduleDef; |
||||
|
||||
public int RID => MetadataTokens.GetRowNumber(handle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => MetadataTokens.GetToken(handle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Offset => metadataFile.MetadataOffset |
||||
+ metadataFile.Metadata.GetTableMetadataOffset(TableIndex.Module) |
||||
+ metadataFile.Metadata.GetTableRowSize(TableIndex.Module) * (RID - 1); |
||||
|
||||
public int Generation => moduleDef.Generation; |
||||
|
||||
public string Name => metadataFile.Metadata.GetString(moduleDef.Name); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Mvid => MetadataTokens.GetHeapOffset(moduleDef.Mvid); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int GenerationId => MetadataTokens.GetHeapOffset(moduleDef.GenerationId); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int BaseGenerationId => MetadataTokens.GetHeapOffset(moduleDef.BaseGenerationId); |
||||
|
||||
public ModuleEntry(MetadataFile metadataFile, ModuleDefinitionHandle handle) |
||||
{ |
||||
this.metadataFile = metadataFile; |
||||
this.handle = handle; |
||||
moduleDef = metadataFile.Metadata.GetModuleDefinition(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Reflection; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the TypeDef table — every type the module defines. The first row is the
|
||||
/// pseudo-type <Module>, owning module-scoped fields and methods. Each row carries
|
||||
/// attributes (visibility, layout, semantics), the optional base type, and pointers
|
||||
/// into the FieldList / MethodList for the type's members.
|
||||
/// </summary>
|
||||
public sealed class TypeDefTableTreeNode : MetadataTableTreeNode<TypeDefTableTreeNode.TypeDefEntry> |
||||
{ |
||||
public TypeDefTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.TypeDef, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<TypeDefEntry> LoadTable() |
||||
{ |
||||
var list = new List<TypeDefEntry>(); |
||||
foreach (var row in metadataFile.Metadata.TypeDefinitions) |
||||
list.Add(new TypeDefEntry(metadataFile, row)); |
||||
return list; |
||||
} |
||||
|
||||
public sealed class TypeDefEntry |
||||
{ |
||||
readonly MetadataFile metadataFile; |
||||
readonly TypeDefinitionHandle handle; |
||||
readonly TypeDefinition typeDef; |
||||
|
||||
public int RID => MetadataTokens.GetRowNumber(handle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => MetadataTokens.GetToken(handle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Offset => metadataFile.MetadataOffset |
||||
+ metadataFile.Metadata.GetTableMetadataOffset(TableIndex.TypeDef) |
||||
+ metadataFile.Metadata.GetTableRowSize(TableIndex.TypeDef) * (RID - 1); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public TypeAttributes Attributes => typeDef.Attributes; |
||||
|
||||
public string Name => metadataFile.Metadata.GetString(typeDef.Name); |
||||
|
||||
public string Namespace => metadataFile.Metadata.GetString(typeDef.Namespace); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int BaseType => MetadataTokens.GetToken(typeDef.BaseType); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int FieldList => MetadataTokens.GetToken(typeDef.GetFields().FirstOrDefault()); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int MethodList => MetadataTokens.GetToken(typeDef.GetMethods().FirstOrDefault()); |
||||
|
||||
public TypeDefEntry(MetadataFile metadataFile, TypeDefinitionHandle handle) |
||||
{ |
||||
this.metadataFile = metadataFile; |
||||
this.handle = handle; |
||||
typeDef = metadataFile.Metadata.GetTypeDefinition(handle); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System.Collections.Generic; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.Metadata.Ecma335; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ILSpy.Metadata.CorTables |
||||
{ |
||||
/// <summary>
|
||||
/// View of the TypeRef table — every external type the module mentions. Each row points
|
||||
/// at the resolution scope (an AssemblyRef, ModuleRef, or another TypeRef for nested
|
||||
/// types) plus the namespace + name of the referenced type.
|
||||
/// </summary>
|
||||
public sealed class TypeRefTableTreeNode : MetadataTableTreeNode<TypeRefTableTreeNode.TypeRefEntry> |
||||
{ |
||||
public TypeRefTableTreeNode(MetadataFile metadataFile) |
||||
: base(TableIndex.TypeRef, metadataFile) |
||||
{ |
||||
} |
||||
|
||||
protected override IReadOnlyList<TypeRefEntry> LoadTable() |
||||
{ |
||||
var list = new List<TypeRefEntry>(); |
||||
foreach (var row in metadataFile.Metadata.TypeReferences) |
||||
list.Add(new TypeRefEntry(metadataFile, row)); |
||||
return list; |
||||
} |
||||
|
||||
public sealed class TypeRefEntry |
||||
{ |
||||
readonly MetadataFile metadataFile; |
||||
readonly TypeReferenceHandle handle; |
||||
readonly TypeReference typeRef; |
||||
|
||||
public int RID => MetadataTokens.GetRowNumber(handle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Token => MetadataTokens.GetToken(handle); |
||||
|
||||
[ColumnInfo("X8")] |
||||
public int Offset => metadataFile.MetadataOffset |
||||
+ metadataFile.Metadata.GetTableMetadataOffset(TableIndex.TypeRef) |
||||
+ metadataFile.Metadata.GetTableRowSize(TableIndex.TypeRef) * (RID - 1); |
||||
|
||||
[ColumnInfo("X8", Kind = ColumnKind.Token)] |
||||
public int ResolutionScope => MetadataTokens.GetToken(typeRef.ResolutionScope); |
||||
|
||||
public string Name => metadataFile.Metadata.GetString(typeRef.Name); |
||||
|
||||
public string Namespace => metadataFile.Metadata.GetString(typeRef.Namespace); |
||||
|
||||
public TypeRefEntry(MetadataFile metadataFile, TypeReferenceHandle handle) |
||||
{ |
||||
this.metadataFile = metadataFile; |
||||
this.handle = handle; |
||||
typeRef = metadataFile.Metadata.GetTypeReference(handle); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue