diff --git a/MetadataProcessor.Shared/Tables/nanoTablesContext.cs b/MetadataProcessor.Shared/Tables/nanoTablesContext.cs
index fdc927b0..0bfb7d7f 100644
--- a/MetadataProcessor.Shared/Tables/nanoTablesContext.cs
+++ b/MetadataProcessor.Shared/Tables/nanoTablesContext.cs
@@ -316,12 +316,12 @@ public ushort GetFieldReferenceId(
// 0: TBL_FieldDef
// 1: TBL_FieldRef
- ushort referenceId = 0xFFFF;
+ ushort referenceId;
NanoClrTable ownerTable = NanoClrTable.TBL_EndOfAssembly;
if (fieldReference is FieldDefinition)
{
- // field reference is internal
+ // field definition is internal
if (FieldsTable.TryGetFieldReferenceId(fieldReference as FieldDefinition, false, out referenceId))
{
// field reference is internal => field definition
@@ -337,6 +337,20 @@ public ushort GetFieldReferenceId(
// field reference is external
ownerTable = NanoClrTable.TBL_FieldRef;
}
+ else if (fieldReference is MemberReference)
+ {
+ // field reference belongs to a TypeSpec
+ // find FieldDef for this
+ FieldReference fieldRef = FieldReferencesTable.Items.FirstOrDefault(m => m.DeclaringType.MetadataToken == fieldReference.DeclaringType.MetadataToken && m.Name == fieldReference.Name);
+
+ if (!FieldReferencesTable.TryGetFieldReferenceId(fieldRef, out referenceId))
+ {
+ Debug.Fail($"Can't find FieldRef for {fieldReference}");
+ }
+
+ // owner is FieldRef
+ ownerTable = NanoClrTable.TBL_FieldRef;
+ }
else
{
Debug.Fail($"Can't find any reference for {fieldReference}");
diff --git a/MetadataProcessor.Shared/Tables/nanoTypeSpecificationsTable.cs b/MetadataProcessor.Shared/Tables/nanoTypeSpecificationsTable.cs
index ea27c951..85825940 100644
--- a/MetadataProcessor.Shared/Tables/nanoTypeSpecificationsTable.cs
+++ b/MetadataProcessor.Shared/Tables/nanoTypeSpecificationsTable.cs
@@ -130,6 +130,21 @@ public TypeReference TryGetTypeSpecification(MetadataToken token)
return _idByTypeSpecifications.FirstOrDefault(typeEntry => typeEntry.Key.MetadataToken == token).Key;
}
+ ///
+ /// Tries to find type reference by the index on the TypeSpec list.
+ ///
+ /// Index of the type reference in the list.
+ /// Returns the type reference if found, otherwise returns null.
+ public TypeReference TryGetTypeReferenceByIndex(ushort index)
+ {
+ if (index >= _idByTypeSpecifications.Count)
+ {
+ return null;
+ }
+
+ return _idByTypeSpecifications.ElementAt(index).Key;
+ }
+
///
public void Write(
nanoBinaryWriter writer)
diff --git a/MetadataProcessor.Shared/nanoAssemblyBuilder.cs b/MetadataProcessor.Shared/nanoAssemblyBuilder.cs
index ce3e0320..89a24689 100644
--- a/MetadataProcessor.Shared/nanoAssemblyBuilder.cs
+++ b/MetadataProcessor.Shared/nanoAssemblyBuilder.cs
@@ -350,8 +350,6 @@ private HashSet BuildDependencyList(MetadataToken token)
if (mr != null &&
mr.ReturnType != null)
{
- parameters = mr.Parameters;
-
if (mr.DeclaringType != null)
{
if (mr.DeclaringType is TypeSpecification)
@@ -359,9 +357,13 @@ private HashSet BuildDependencyList(MetadataToken token)
// Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it
if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(mr.DeclaringType, out ushort referenceId))
{
+ // add "fabricated" token for TypeSpec using the referenceId as RID
set.Add(new MetadataToken(
TokenType.TypeSpec,
referenceId));
+
+ // add the metadata token for the element type
+ set.Add(mr.DeclaringType.GetElementType().MetadataToken);
}
else
{
@@ -460,9 +462,13 @@ private HashSet BuildDependencyList(MetadataToken token)
// Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it
if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(fr.DeclaringType, out ushort referenceId))
{
+ // add "fabricated" token for TypeSpec using the referenceId as RID
set.Add(new MetadataToken(
TokenType.TypeSpec,
referenceId));
+
+ // add the metadata token for the element type
+ set.Add(fr.DeclaringType.GetElementType().MetadataToken);
}
else
{
@@ -518,14 +524,33 @@ private HashSet BuildDependencyList(MetadataToken token)
break;
case TokenType.TypeSpec:
- var ts = _tablesContext.TypeSpecificationsTable.TryGetTypeSpecification(token);
-
- if (ts != null)
+ // Developer notes:
+ // Because the issue with Mono.Cecil not providing the correct metadata token for TypeSpec,
+ // need to search the TypeSpec token in the two "formats".
+ // 1. The original token as provided by Mono.Cecil
+ // 2. The "fabricated" token, which is the one that is used in the TypeSpec table
+ // It's OK to add both to the set because they end up referencing to the same type.
+ // Anyways, as this a minimize operation, it's preferable to have both rather than none.
+
+ // start searching for metadata token
+ TypeReference ts1 = _tablesContext.TypeSpecificationsTable.TryGetTypeSpecification(token);
+
+ if (ts1 != null)
{
+ // found it, let's add it
set.Add(token);
}
- Debug.Assert(ts != null);
+ // now try to find the TypeSpec from the "fabricated" token, using the RID
+ TypeReference ts2 = _tablesContext.TypeSpecificationsTable.TryGetTypeReferenceByIndex((ushort)token.RID);
+
+ if (ts2 != null)
+ {
+ set.Add(ts2.MetadataToken);
+ }
+
+ // sanity check
+ Debug.Assert(ts1 != null || ts2 != null);
break;
@@ -807,10 +832,12 @@ private HashSet BuildDependencyList(MetadataToken token)
// Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it
if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(v.VariableType, out ushort referenceId))
{
+ // add "fabricated" token for TypeSpec using the referenceId as RID
set.Add(new MetadataToken(
TokenType.TypeSpec,
referenceId));
+ // add the metadata token for the element type
set.Add(v.VariableType.GetElementType().MetadataToken);
}
else
@@ -844,9 +871,13 @@ private HashSet BuildDependencyList(MetadataToken token)
// Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it
if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(methodReferenceType.DeclaringType, out referenceId))
{
+ // add "fabricated" token for TypeSpec using the referenceId as RID
set.Add(new MetadataToken(
TokenType.TypeSpec,
referenceId));
+
+ // add the metadata token for the element type
+ set.Add(methodReferenceType.DeclaringType.GetElementType().MetadataToken);
}
else
{
@@ -877,9 +908,13 @@ i.Operand is GenericInstanceMethod ||
// Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it
if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(opType, out ushort referenceId))
{
+ // add "fabricated" token for TypeSpec using the referenceId as RID
set.Add(new MetadataToken(
TokenType.TypeSpec,
referenceId));
+
+ // add the metadata token for the element type
+ set.Add(opType.GetElementType().MetadataToken);
}
else
{
diff --git a/MetadataProcessor.Shared/nanoDumperGenerator.cs b/MetadataProcessor.Shared/nanoDumperGenerator.cs
index d321f3a8..888515c2 100644
--- a/MetadataProcessor.Shared/nanoDumperGenerator.cs
+++ b/MetadataProcessor.Shared/nanoDumperGenerator.cs
@@ -734,6 +734,25 @@ private void DumpTypeSpecifications(
}
}
+ foreach (var fr in _tablesContext.FieldReferencesTable.Items)
+ {
+ if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(fr.DeclaringType, out ushort referenceId) &&
+ referenceId == index)
+ {
+ var memberRef = new MemberRef()
+ {
+ Name = fr.Name
+ };
+ if (_tablesContext.FieldReferencesTable.TryGetFieldReferenceId(fr, out ushort fieldRefId))
+ {
+ realToken = fr.MetadataToken.ToInt32().ToString("X8");
+ memberRef.ReferenceId = $"[{new nanoMetadataToken(NanoClrTable.TBL_FieldRef, fieldRefId)}] /*{realToken}*/";
+ memberRef.Signature = fr.FieldType.TypeSignatureAsString();
+ }
+ typeSpec.MemberReferences.Add(memberRef);
+ }
+ }
+
Debug.Assert(typeSpec.MemberReferences.Count > 0, $"Couldn't find any MethodRef for TypeSpec[{typeReference}] {typeReference.FullName}");
}
diff --git a/MetadataProcessor.Tests/Core/Utility/DumperTests.cs b/MetadataProcessor.Tests/Core/Utility/DumperTests.cs
index 284fdf79..b6f3b274 100644
--- a/MetadataProcessor.Tests/Core/Utility/DumperTests.cs
+++ b/MetadataProcessor.Tests/Core/Utility/DumperTests.cs
@@ -133,7 +133,7 @@ public void DumpAssemblyTest()
nanoTablesContext.TypeReferencesTable.TryGetTypeReferenceId(type1.BaseType, out baseTypeReferenceId);
typeFlags = (uint)nanoTypeDefinitionTable.GetFlags(type1, nanoTablesContext.MethodDefinitionTable);
- Assert.IsTrue(dumpFileContent.Contains($"TypeDef {nanoDumperGenerator.TypeDefRefIdToString(type1, typeRefId)}\r\n-------------------------------------------------------\r\n '{type1.Name}'\r\n Flags: {typeFlags:X8}\r\n Extends: {nanoDumperGenerator.TypeDefExtendsTypeToString(type1.BaseType, baseTypeReferenceId)}\r\n Enclosed: TestNFApp.OneClassOverAll[04000000] /*0200001B*/"));
+ Assert.IsTrue(dumpFileContent.Contains($"TypeDef {nanoDumperGenerator.TypeDefRefIdToString(type1, typeRefId)}\r\n-------------------------------------------------------\r\n '{type1.Name}'\r\n Flags: {typeFlags:X8}\r\n Extends: {nanoDumperGenerator.TypeDefExtendsTypeToString(type1.BaseType, baseTypeReferenceId)}\r\n Enclosed: TestNFApp.OneClassOverAll[04000000] /*0200001D*/"));
// String heap
foreach (string stringKey in nanoTablesContext.StringTable.GetItems().Keys)
diff --git a/MetadataProcessor.Tests/TestNFApp/Program.cs b/MetadataProcessor.Tests/TestNFApp/Program.cs
index a135f8e9..e0ed8b8c 100644
--- a/MetadataProcessor.Tests/TestNFApp/Program.cs
+++ b/MetadataProcessor.Tests/TestNFApp/Program.cs
@@ -80,6 +80,7 @@ public static void Main()
///////////////////////////////////////////////////////////////////
// Generics Tests
_ = new GenericClassTests();
+ _ = new StatckTests();
// null attributes tests
Console.WriteLine("Null attributes tests");
diff --git a/MetadataProcessor.Tests/TestNFApp/StackClass.cs b/MetadataProcessor.Tests/TestNFApp/StackClass.cs
new file mode 100644
index 00000000..887d0864
--- /dev/null
+++ b/MetadataProcessor.Tests/TestNFApp/StackClass.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace TestNFApp
+{
+ public class Stack
+ {
+ private readonly T[] _items;
+ private int _count;
+
+ public Stack(int size) => _items = new T[size];
+
+ public void Push(T item) => _items[_count++] = item;
+
+ public T Pop() => _items[--_count];
+ }
+
+ public class StatckTests
+ {
+ public StatckTests()
+ {
+ // Create a stack of integers
+ Stack intStack = new Stack(5);
+
+ intStack.Push(1);
+ intStack.Push(2);
+
+ Console.WriteLine($"First value is{intStack.Pop()}");
+ Console.WriteLine($"Second value is{intStack.Pop()}");
+
+ // Create a stack of strings
+ Stack stringStack = new Stack(5);
+
+ stringStack.Push("Hello");
+ stringStack.Push("World");
+
+ Console.WriteLine($"First value is {stringStack.Pop()}");
+ Console.WriteLine($"Second value is {stringStack.Pop()}");
+ }
+ }
+}
diff --git a/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj b/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj
index 10f82e28..d2d5a693 100644
--- a/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj
+++ b/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj
@@ -23,6 +23,7 @@
+