diff --git a/ILSpy/Metadata/CorTables/ConstantTableTreeNode.cs b/ILSpy/Metadata/CorTables/ConstantTableTreeNode.cs
new file mode 100644
index 000000000..bf2a5cca6
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/ConstantTableTreeNode.cs
@@ -0,0 +1,80 @@
+// 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
+{
+ ///
+ /// View of the Constant table — compile-time constants attached to fields, parameters,
+ /// or properties. The Type column is the primitive type code; Value points at a blob
+ /// holding the literal payload.
+ ///
+ public sealed class ConstantTableTreeNode : MetadataTableTreeNode
+ {
+ public ConstantTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.Constant, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ for (int row = 1; row <= metadataFile.Metadata.GetTableRowCount(TableIndex.Constant); row++)
+ list.Add(new ConstantEntry(metadataFile, MetadataTokens.ConstantHandle(row)));
+ return list;
+ }
+
+ public sealed class ConstantEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly ConstantHandle handle;
+ readonly Constant constant;
+
+ 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.Constant)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.Constant) * (RID - 1);
+
+ [ColumnInfo("X8")]
+ public ConstantTypeCode Type => constant.TypeCode;
+
+ [ColumnInfo("X8", Kind = ColumnKind.Token)]
+ public int Parent => MetadataTokens.GetToken(constant.Parent);
+
+ [ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
+ public int Value => MetadataTokens.GetHeapOffset(constant.Value);
+
+ public ConstantEntry(MetadataFile metadataFile, ConstantHandle handle)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ constant = metadataFile.Metadata.GetConstant(handle);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/CorTables/EventTableTreeNode.cs b/ILSpy/Metadata/CorTables/EventTableTreeNode.cs
new file mode 100644
index 000000000..1c3014de8
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/EventTableTreeNode.cs
@@ -0,0 +1,80 @@
+// 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;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+
+using ICSharpCode.Decompiler.Metadata;
+
+namespace ILSpy.Metadata.CorTables
+{
+ ///
+ /// View of the Event table — every CLR event the module's types declare. Each row
+ /// references the event's delegate type as a TypeDefOrRef coded token; add/remove/raise
+ /// accessor bindings live in MethodSemantics.
+ ///
+ public sealed class EventTableTreeNode : MetadataTableTreeNode
+ {
+ public EventTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.Event, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ foreach (var row in metadataFile.Metadata.EventDefinitions)
+ list.Add(new EventDefEntry(metadataFile, row));
+ return list;
+ }
+
+ public sealed class EventDefEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly EventDefinitionHandle handle;
+ readonly EventDefinition eventDef;
+
+ 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.Event)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.Event) * (RID - 1);
+
+ [ColumnInfo("X8")]
+ public EventAttributes Attributes => eventDef.Attributes;
+
+ public string Name => metadataFile.Metadata.GetString(eventDef.Name);
+
+ [ColumnInfo("X8", Kind = ColumnKind.Token)]
+ public int Type => MetadataTokens.GetToken(eventDef.Type);
+
+ public EventDefEntry(MetadataFile metadataFile, EventDefinitionHandle handle)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ eventDef = metadataFile.Metadata.GetEventDefinition(handle);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/CorTables/ExportedTypeTableTreeNode.cs b/ILSpy/Metadata/CorTables/ExportedTypeTableTreeNode.cs
new file mode 100644
index 000000000..b36199fe1
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/ExportedTypeTableTreeNode.cs
@@ -0,0 +1,86 @@
+// 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;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+
+using ICSharpCode.Decompiler.Metadata;
+
+namespace ILSpy.Metadata.CorTables
+{
+ ///
+ /// View of the ExportedType table — types this assembly forwards to (or re-exports
+ /// from) another assembly. Common in type-forwarding scenarios where mscorlib.dll
+ /// exposes types that physically live in System.Runtime.dll.
+ ///
+ public sealed class ExportedTypeTableTreeNode : MetadataTableTreeNode
+ {
+ public ExportedTypeTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.ExportedType, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ var metadata = metadataFile.Metadata;
+ foreach (var row in metadata.ExportedTypes)
+ list.Add(new ExportedTypeEntry(metadataFile, row, metadata.GetExportedType(row)));
+ return list;
+ }
+
+ public sealed class ExportedTypeEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly ExportedTypeHandle handle;
+ readonly ExportedType type;
+
+ 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.ExportedType)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.ExportedType) * (RID - 1);
+
+ [ColumnInfo("X8")]
+ public TypeAttributes Attributes => type.Attributes;
+
+ [ColumnInfo("X8")]
+ public int TypeDefId => type.GetTypeDefinitionId();
+
+ public string TypeName => metadataFile.Metadata.GetString(type.Name);
+
+ public string TypeNamespace => metadataFile.Metadata.GetString(type.Namespace);
+
+ [ColumnInfo("X8", Kind = ColumnKind.Token)]
+ public int Implementation => MetadataTokens.GetToken(type.Implementation);
+
+ public ExportedTypeEntry(MetadataFile metadataFile, ExportedTypeHandle handle, ExportedType type)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ this.type = type;
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/CorTables/GenericParamConstraintTableTreeNode.cs b/ILSpy/Metadata/CorTables/GenericParamConstraintTableTreeNode.cs
new file mode 100644
index 000000000..e159de46b
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/GenericParamConstraintTableTreeNode.cs
@@ -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
+{
+ ///
+ /// View of the GenericParamConstraint table — bounds applied to generic parameters
+ /// (where T : SomeBase, IEnumerable<X>). Each row pairs a GenericParam
+ /// owner with a TypeDefOrRef coded token naming the constraining type.
+ ///
+ public sealed class GenericParamConstraintTableTreeNode : MetadataTableTreeNode
+ {
+ public GenericParamConstraintTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.GenericParamConstraint, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ var metadata = metadataFile.Metadata;
+ for (int row = 1; row <= metadata.GetTableRowCount(TableIndex.GenericParamConstraint); row++)
+ list.Add(new GenericParamConstraintEntry(metadataFile, MetadataTokens.GenericParameterConstraintHandle(row)));
+ return list;
+ }
+
+ public sealed class GenericParamConstraintEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly GenericParameterConstraintHandle handle;
+ readonly GenericParameterConstraint genericParamConstraint;
+
+ 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.GenericParamConstraint)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.GenericParamConstraint) * (RID - 1);
+
+ [ColumnInfo("X8", Kind = ColumnKind.Token)]
+ public int Owner => MetadataTokens.GetToken(genericParamConstraint.Parameter);
+
+ [ColumnInfo("X8", Kind = ColumnKind.Token)]
+ public int Type => MetadataTokens.GetToken(genericParamConstraint.Type);
+
+ public GenericParamConstraintEntry(MetadataFile metadataFile, GenericParameterConstraintHandle handle)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ genericParamConstraint = metadataFile.Metadata.GetGenericParameterConstraint(handle);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/CorTables/GenericParamTableTreeNode.cs b/ILSpy/Metadata/CorTables/GenericParamTableTreeNode.cs
new file mode 100644
index 000000000..796c0869e
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/GenericParamTableTreeNode.cs
@@ -0,0 +1,82 @@
+// 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;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+
+using ICSharpCode.Decompiler.Metadata;
+
+namespace ILSpy.Metadata.CorTables
+{
+ ///
+ /// View of the GenericParam table — every type or method generic-parameter slot. Owner
+ /// is a TypeOrMethodDef coded token; Number is the parameter's 0-based index inside
+ /// its owner's type-parameter list.
+ ///
+ public sealed class GenericParamTableTreeNode : MetadataTableTreeNode
+ {
+ public GenericParamTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.GenericParam, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ for (int row = 1; row <= metadataFile.Metadata.GetTableRowCount(TableIndex.GenericParam); row++)
+ list.Add(new GenericParamEntry(metadataFile, MetadataTokens.GenericParameterHandle(row)));
+ return list;
+ }
+
+ public sealed class GenericParamEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly GenericParameterHandle handle;
+ readonly GenericParameter genericParam;
+
+ 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.GenericParam)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.GenericParam) * (RID - 1);
+
+ public int Number => genericParam.Index;
+
+ [ColumnInfo("X8")]
+ public GenericParameterAttributes Attributes => genericParam.Attributes;
+
+ [ColumnInfo("X8", Kind = ColumnKind.Token)]
+ public int Owner => MetadataTokens.GetToken(genericParam.Parent);
+
+ public string Name => metadataFile.Metadata.GetString(genericParam.Name);
+
+ public GenericParamEntry(MetadataFile metadataFile, GenericParameterHandle handle)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ genericParam = metadataFile.Metadata.GetGenericParameter(handle);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/CorTables/ManifestResourceTableTreeNode.cs b/ILSpy/Metadata/CorTables/ManifestResourceTableTreeNode.cs
new file mode 100644
index 000000000..83dfbeca8
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/ManifestResourceTableTreeNode.cs
@@ -0,0 +1,81 @@
+// 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;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+
+using ICSharpCode.Decompiler.Metadata;
+
+namespace ILSpy.Metadata.CorTables
+{
+ ///
+ /// View of the ManifestResource table — every embedded or linked resource the assembly
+ /// manifest publishes. Implementation is an Implementation coded token: nil for embedded
+ /// resources (data lives at .text+offset), otherwise an AssemblyFile or AssemblyRef
+ /// pointing at the holder of the resource bytes.
+ ///
+ public sealed class ManifestResourceTableTreeNode : MetadataTableTreeNode
+ {
+ public ManifestResourceTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.ManifestResource, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ foreach (var row in metadataFile.Metadata.ManifestResources)
+ list.Add(new ManifestResourceEntry(metadataFile, row));
+ return list;
+ }
+
+ public sealed class ManifestResourceEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly ManifestResourceHandle handle;
+ readonly ManifestResource manifestResource;
+
+ 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.ManifestResource)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.ManifestResource) * (RID - 1);
+
+ [ColumnInfo("X8")]
+ public ManifestResourceAttributes Attributes => manifestResource.Attributes;
+
+ public string Name => metadataFile.Metadata.GetString(manifestResource.Name);
+
+ [ColumnInfo("X8", Kind = ColumnKind.Token)]
+ public int Implementation => MetadataTokens.GetToken(manifestResource.Implementation);
+
+ public ManifestResourceEntry(MetadataFile metadataFile, ManifestResourceHandle handle)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ manifestResource = metadataFile.Metadata.GetManifestResource(handle);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/CorTables/MethodSpecTableTreeNode.cs b/ILSpy/Metadata/CorTables/MethodSpecTableTreeNode.cs
new file mode 100644
index 000000000..8e1d36698
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/MethodSpecTableTreeNode.cs
@@ -0,0 +1,77 @@
+// 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
+{
+ ///
+ /// View of the MethodSpec table — concrete instantiations of generic methods like
+ /// List<int>.Add. Each row points back at the open generic method
+ /// (MethodDef or MemberRef) and carries a blob holding the type-argument list.
+ ///
+ public sealed class MethodSpecTableTreeNode : MetadataTableTreeNode
+ {
+ public MethodSpecTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.MethodSpec, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ foreach (var row in metadataFile.Metadata.GetMethodSpecifications())
+ list.Add(new MethodSpecEntry(metadataFile, row));
+ return list;
+ }
+
+ public sealed class MethodSpecEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly MethodSpecificationHandle handle;
+ readonly MethodSpecification methodSpec;
+
+ 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.MethodSpec)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.MethodSpec) * (RID - 1);
+
+ [ColumnInfo("X8", Kind = ColumnKind.Token)]
+ public int Method => MetadataTokens.GetToken(methodSpec.Method);
+
+ [ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
+ public int Signature => MetadataTokens.GetHeapOffset(methodSpec.Signature);
+
+ public MethodSpecEntry(MetadataFile metadataFile, MethodSpecificationHandle handle)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ methodSpec = metadataFile.Metadata.GetMethodSpecification(handle);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/CorTables/ModuleRefTableTreeNode.cs b/ILSpy/Metadata/CorTables/ModuleRefTableTreeNode.cs
new file mode 100644
index 000000000..d40abe6da
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/ModuleRefTableTreeNode.cs
@@ -0,0 +1,72 @@
+// 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
+{
+ ///
+ /// View of the ModuleRef table — every external .netmodule the assembly P/Invokes into
+ /// or otherwise references by name. Carries just the module's name string handle.
+ ///
+ public sealed class ModuleRefTableTreeNode : MetadataTableTreeNode
+ {
+ public ModuleRefTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.ModuleRef, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ foreach (var row in metadataFile.Metadata.GetModuleReferences())
+ list.Add(new ModuleRefEntry(metadataFile, row));
+ return list;
+ }
+
+ public sealed class ModuleRefEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly ModuleReferenceHandle handle;
+ readonly ModuleReference moduleRef;
+
+ 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.ModuleRef)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.ModuleRef) * (RID - 1);
+
+ public string Name => metadataFile.Metadata.GetString(moduleRef.Name);
+
+ public ModuleRefEntry(MetadataFile metadataFile, ModuleReferenceHandle handle)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ moduleRef = metadataFile.Metadata.GetModuleReference(handle);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/CorTables/PropertyTableTreeNode.cs b/ILSpy/Metadata/CorTables/PropertyTableTreeNode.cs
new file mode 100644
index 000000000..6d16d0dd6
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/PropertyTableTreeNode.cs
@@ -0,0 +1,80 @@
+// 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;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+
+using ICSharpCode.Decompiler.Metadata;
+
+namespace ILSpy.Metadata.CorTables
+{
+ ///
+ /// View of the Property table — every property the module's types declare. Method-level
+ /// accessor binding lives in MethodSemantics; this table just carries each property's
+ /// attributes, name, and signature blob.
+ ///
+ public sealed class PropertyTableTreeNode : MetadataTableTreeNode
+ {
+ public PropertyTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.Property, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ foreach (var row in metadataFile.Metadata.PropertyDefinitions)
+ list.Add(new PropertyDefEntry(metadataFile, row));
+ return list;
+ }
+
+ public sealed class PropertyDefEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly PropertyDefinitionHandle handle;
+ readonly PropertyDefinition propertyDef;
+
+ 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.Property)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.Property) * (RID - 1);
+
+ [ColumnInfo("X8")]
+ public PropertyAttributes Attributes => propertyDef.Attributes;
+
+ public string Name => metadataFile.Metadata.GetString(propertyDef.Name);
+
+ [ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
+ public int Signature => MetadataTokens.GetHeapOffset(propertyDef.Signature);
+
+ public PropertyDefEntry(MetadataFile metadataFile, PropertyDefinitionHandle handle)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ propertyDef = metadataFile.Metadata.GetPropertyDefinition(handle);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/CorTables/TypeSpecTableTreeNode.cs b/ILSpy/Metadata/CorTables/TypeSpecTableTreeNode.cs
new file mode 100644
index 000000000..8542171c9
--- /dev/null
+++ b/ILSpy/Metadata/CorTables/TypeSpecTableTreeNode.cs
@@ -0,0 +1,74 @@
+// 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
+{
+ ///
+ /// View of the TypeSpec table — instantiated generic types and other constructed type
+ /// shapes (arrays, pointers, modreq/modopt) referenced from instructions and signatures.
+ /// Each row points at a blob signature describing the constructed type.
+ ///
+ public sealed class TypeSpecTableTreeNode : MetadataTableTreeNode
+ {
+ public TypeSpecTableTreeNode(MetadataFile metadataFile)
+ : base(TableIndex.TypeSpec, metadataFile)
+ {
+ }
+
+ protected override IReadOnlyList LoadTable()
+ {
+ var list = new List();
+ foreach (var row in metadataFile.Metadata.GetTypeSpecifications())
+ list.Add(new TypeSpecEntry(metadataFile, row));
+ return list;
+ }
+
+ public sealed class TypeSpecEntry
+ {
+ readonly MetadataFile metadataFile;
+ readonly TypeSpecificationHandle handle;
+ readonly TypeSpecification typeSpec;
+
+ 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.TypeSpec)
+ + metadataFile.Metadata.GetTableRowSize(TableIndex.TypeSpec) * (RID - 1);
+
+ [ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
+ public int Signature => MetadataTokens.GetHeapOffset(typeSpec.Signature);
+
+ public TypeSpecEntry(MetadataFile metadataFile, TypeSpecificationHandle handle)
+ {
+ this.metadataFile = metadataFile;
+ this.handle = handle;
+ typeSpec = metadataFile.Metadata.GetTypeSpecification(handle);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/MetadataTablesTreeNode.cs b/ILSpy/Metadata/MetadataTablesTreeNode.cs
index e757a4d73..542ced37d 100644
--- a/ILSpy/Metadata/MetadataTablesTreeNode.cs
+++ b/ILSpy/Metadata/MetadataTablesTreeNode.cs
@@ -81,9 +81,19 @@ namespace ILSpy.Metadata
TableIndex.MethodDef => new MethodTableTreeNode(metadataFile),
TableIndex.Param => new ParamTableTreeNode(metadataFile),
TableIndex.MemberRef => new MemberRefTableTreeNode(metadataFile),
+ TableIndex.Constant => new ConstantTableTreeNode(metadataFile),
TableIndex.CustomAttribute => new CustomAttributeTableTreeNode(metadataFile),
+ TableIndex.Event => new EventTableTreeNode(metadataFile),
+ TableIndex.Property => new PropertyTableTreeNode(metadataFile),
+ TableIndex.ModuleRef => new ModuleRefTableTreeNode(metadataFile),
+ TableIndex.TypeSpec => new TypeSpecTableTreeNode(metadataFile),
TableIndex.Assembly => new AssemblyTableTreeNode(metadataFile),
TableIndex.AssemblyRef => new AssemblyRefTableTreeNode(metadataFile),
+ TableIndex.ExportedType => new ExportedTypeTableTreeNode(metadataFile),
+ TableIndex.ManifestResource => new ManifestResourceTableTreeNode(metadataFile),
+ TableIndex.GenericParam => new GenericParamTableTreeNode(metadataFile),
+ TableIndex.MethodSpec => new MethodSpecTableTreeNode(metadataFile),
+ TableIndex.GenericParamConstraint => new GenericParamConstraintTableTreeNode(metadataFile),
_ => new UnsupportedMetadataTableTreeNode(table, metadataFile),
};
}