Skip to content

Commit 9cb7eff

Browse files
authored
Fix generated metadata in TypeDef processing (#176)
***NO_CI***
1 parent 67aae15 commit 9cb7eff

File tree

5 files changed

+192
-50
lines changed

5 files changed

+192
-50
lines changed

MetadataProcessor.Shared/Tables/nanoSignaturesTable.cs

Lines changed: 113 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
//
2-
// Copyright (c) .NET Foundation and Contributors
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
34
// Original work from Oleg Rakhmatulin.
4-
// See LICENSE file in the project root for full license information.
5-
//
65

7-
using Mono.Cecil;
8-
using Mono.Cecil.Cil;
9-
using Mono.Collections.Generic;
10-
using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
116
using System;
127
using System.Collections.Generic;
138
using System.Diagnostics;
149
using System.IO;
1510
using System.Linq;
11+
using Mono.Cecil;
12+
using Mono.Cecil.Cil;
13+
using Mono.Collections.Generic;
14+
using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
1615

1716
namespace nanoFramework.Tools.MetadataProcessor
1817
{
@@ -41,35 +40,67 @@ public int GetHashCode(byte[] that)
4140
}
4241
}
4342

44-
internal static readonly IDictionary<string, nanoCLR_DataType> PrimitiveTypes =
43+
private static readonly IDictionary<string, nanoCLR_DataType> s_primitiveTypes =
4544
new Dictionary<string, nanoCLR_DataType>(StringComparer.Ordinal);
4645

47-
static nanoSignaturesTable()
48-
{
49-
PrimitiveTypes.Add(typeof(void).FullName, nanoCLR_DataType.DATATYPE_VOID);
50-
51-
PrimitiveTypes.Add(typeof(sbyte).FullName, nanoCLR_DataType.DATATYPE_I1);
52-
PrimitiveTypes.Add(typeof(short).FullName, nanoCLR_DataType.DATATYPE_I2);
53-
PrimitiveTypes.Add(typeof(int).FullName, nanoCLR_DataType.DATATYPE_I4);
54-
PrimitiveTypes.Add(typeof(long).FullName, nanoCLR_DataType.DATATYPE_I8);
55-
56-
PrimitiveTypes.Add(typeof(byte).FullName, nanoCLR_DataType.DATATYPE_U1);
57-
PrimitiveTypes.Add(typeof(ushort).FullName, nanoCLR_DataType.DATATYPE_U2);
58-
PrimitiveTypes.Add(typeof(uint).FullName, nanoCLR_DataType.DATATYPE_U4);
59-
PrimitiveTypes.Add(typeof(ulong).FullName, nanoCLR_DataType.DATATYPE_U8);
60-
61-
PrimitiveTypes.Add(typeof(float).FullName, nanoCLR_DataType.DATATYPE_R4);
62-
PrimitiveTypes.Add(typeof(double).FullName, nanoCLR_DataType.DATATYPE_R8);
63-
64-
PrimitiveTypes.Add(typeof(char).FullName, nanoCLR_DataType.DATATYPE_CHAR);
65-
PrimitiveTypes.Add(typeof(string).FullName, nanoCLR_DataType.DATATYPE_STRING);
66-
PrimitiveTypes.Add(typeof(bool).FullName, nanoCLR_DataType.DATATYPE_BOOLEAN);
46+
/// <summary>
47+
/// Built-in types (see flags in c_CLR_RT_DataTypeLookup at CLR Core code)
48+
/// </summary>
49+
private static readonly IDictionary<string, nanoCLR_DataType> s_builtInTypes =
50+
new Dictionary<string, nanoCLR_DataType>(StringComparer.Ordinal);
6751

68-
PrimitiveTypes.Add(typeof(object).FullName, nanoCLR_DataType.DATATYPE_OBJECT);
69-
PrimitiveTypes.Add(typeof(IntPtr).FullName, nanoCLR_DataType.DATATYPE_I4);
70-
PrimitiveTypes.Add(typeof(UIntPtr).FullName, nanoCLR_DataType.DATATYPE_U4);
52+
public static IDictionary<string, nanoCLR_DataType> PrimitiveTypes => s_primitiveTypes;
7153

72-
PrimitiveTypes.Add(typeof(WeakReference).FullName, nanoCLR_DataType.DATATYPE_WEAKCLASS);
54+
static nanoSignaturesTable()
55+
{
56+
s_primitiveTypes.Add(typeof(void).FullName, nanoCLR_DataType.DATATYPE_VOID);
57+
58+
s_primitiveTypes.Add(typeof(sbyte).FullName, nanoCLR_DataType.DATATYPE_I1);
59+
s_primitiveTypes.Add(typeof(short).FullName, nanoCLR_DataType.DATATYPE_I2);
60+
s_primitiveTypes.Add(typeof(int).FullName, nanoCLR_DataType.DATATYPE_I4);
61+
s_primitiveTypes.Add(typeof(long).FullName, nanoCLR_DataType.DATATYPE_I8);
62+
63+
s_primitiveTypes.Add(typeof(byte).FullName, nanoCLR_DataType.DATATYPE_U1);
64+
s_primitiveTypes.Add(typeof(ushort).FullName, nanoCLR_DataType.DATATYPE_U2);
65+
s_primitiveTypes.Add(typeof(uint).FullName, nanoCLR_DataType.DATATYPE_U4);
66+
s_primitiveTypes.Add(typeof(ulong).FullName, nanoCLR_DataType.DATATYPE_U8);
67+
68+
s_primitiveTypes.Add(typeof(float).FullName, nanoCLR_DataType.DATATYPE_R4);
69+
s_primitiveTypes.Add(typeof(double).FullName, nanoCLR_DataType.DATATYPE_R8);
70+
71+
s_primitiveTypes.Add(typeof(char).FullName, nanoCLR_DataType.DATATYPE_CHAR);
72+
s_primitiveTypes.Add(typeof(string).FullName, nanoCLR_DataType.DATATYPE_STRING);
73+
s_primitiveTypes.Add(typeof(bool).FullName, nanoCLR_DataType.DATATYPE_BOOLEAN);
74+
75+
s_primitiveTypes.Add(typeof(object).FullName, nanoCLR_DataType.DATATYPE_OBJECT);
76+
s_primitiveTypes.Add(typeof(IntPtr).FullName, nanoCLR_DataType.DATATYPE_I4);
77+
s_primitiveTypes.Add(typeof(UIntPtr).FullName, nanoCLR_DataType.DATATYPE_U4);
78+
79+
s_primitiveTypes.Add(typeof(WeakReference).FullName, nanoCLR_DataType.DATATYPE_WEAKCLASS);
80+
81+
// from c_CLR_RT_DataTypeLookup at CLR Core code
82+
s_builtInTypes.Add(typeof(bool).FullName, nanoCLR_DataType.DATATYPE_BOOLEAN);
83+
s_builtInTypes.Add(typeof(char).FullName, nanoCLR_DataType.DATATYPE_CHAR);
84+
s_builtInTypes.Add(typeof(sbyte).FullName, nanoCLR_DataType.DATATYPE_I1);
85+
s_builtInTypes.Add(typeof(byte).FullName, nanoCLR_DataType.DATATYPE_U1);
86+
s_builtInTypes.Add(typeof(short).FullName, nanoCLR_DataType.DATATYPE_I2);
87+
s_builtInTypes.Add(typeof(ushort).FullName, nanoCLR_DataType.DATATYPE_U2);
88+
s_builtInTypes.Add(typeof(int).FullName, nanoCLR_DataType.DATATYPE_I4);
89+
s_builtInTypes.Add(typeof(uint).FullName, nanoCLR_DataType.DATATYPE_U4);
90+
s_builtInTypes.Add(typeof(long).FullName, nanoCLR_DataType.DATATYPE_I8);
91+
s_builtInTypes.Add(typeof(ulong).FullName, nanoCLR_DataType.DATATYPE_U8);
92+
s_builtInTypes.Add(typeof(float).FullName, nanoCLR_DataType.DATATYPE_R4);
93+
s_builtInTypes.Add(typeof(double).FullName, nanoCLR_DataType.DATATYPE_R8);
94+
95+
s_builtInTypes.Add(typeof(DateTime).FullName, nanoCLR_DataType.DATATYPE_DATETIME);
96+
s_builtInTypes.Add(typeof(TimeSpan).FullName, nanoCLR_DataType.DATATYPE_TIMESPAN);
97+
s_builtInTypes.Add(typeof(string).FullName, nanoCLR_DataType.DATATYPE_STRING);
98+
99+
s_builtInTypes.Add("System.RuntimeTypeHandle", nanoCLR_DataType.DATATYPE_REFLECTION);
100+
s_builtInTypes.Add("System.RuntimeFieldHandle", nanoCLR_DataType.DATATYPE_REFLECTION);
101+
s_builtInTypes.Add("System.RuntimeMethodHandle", nanoCLR_DataType.DATATYPE_REFLECTION);
102+
103+
s_builtInTypes.Add(typeof(WeakReference).FullName, nanoCLR_DataType.DATATYPE_WEAKCLASS);
73104
}
74105

75106
/// <summary>
@@ -273,8 +304,9 @@ public void WriteDataType(
273304
return;
274305
}
275306

276-
nanoCLR_DataType dataType;
277-
if (PrimitiveTypes.TryGetValue(typeDefinition.FullName, out dataType))
307+
if (s_primitiveTypes.TryGetValue(
308+
typeDefinition.FullName,
309+
out nanoCLR_DataType dataType))
278310
{
279311
writer.WriteByte((byte)dataType);
280312
return;
@@ -387,6 +419,51 @@ public void WriteDataType(
387419
writer.WriteByte(0x00);
388420
}
389421

422+
/// <summary>
423+
/// Writes data type for type reference.
424+
/// </summary>
425+
/// <param name="typeDefinition">Type reference or definition in Mono.Cecil format.</param>
426+
/// <param name="writer">Target binary writer for writing signature information.</param>
427+
public void WriteDataTypeForTypeDef(TypeDefinition typeDefinition, nanoBinaryWriter writer)
428+
{
429+
// start checking with the built-in types
430+
if (s_builtInTypes.TryGetValue(
431+
typeDefinition.FullName,
432+
out nanoCLR_DataType dataType))
433+
{
434+
writer.WriteByte((byte)dataType);
435+
}
436+
else
437+
{
438+
// check order matters because some types are derived from others
439+
if (typeDefinition.IsEnum)
440+
{
441+
FieldDefinition baseTypeValue = typeDefinition.Fields.FirstOrDefault(item => item.IsSpecialName);
442+
443+
if (baseTypeValue != null)
444+
{
445+
WriteTypeInfo(baseTypeValue.FieldType, writer);
446+
}
447+
else
448+
{
449+
writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_I4);
450+
}
451+
}
452+
else if (typeDefinition.IsValueType)
453+
{
454+
writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_VALUETYPE);
455+
}
456+
else if (typeDefinition.IsClass || typeDefinition.IsInterface)
457+
{
458+
writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_CLASS);
459+
}
460+
else
461+
{
462+
Debug.Fail("Gotcha!");
463+
}
464+
}
465+
}
466+
390467
/// <inheritdoc/>
391468
public void Write(
392469
nanoBinaryWriter writer)
@@ -567,7 +644,7 @@ private void WriteAttributeArgumentValue(
567644
CustomAttributeArgument argument)
568645
{
569646
nanoCLR_DataType dataType;
570-
if (PrimitiveTypes.TryGetValue(argument.Type.FullName, out dataType))
647+
if (s_primitiveTypes.TryGetValue(argument.Type.FullName, out dataType))
571648
{
572649
switch (dataType)
573650
{

MetadataProcessor.Shared/Tables/nanoTypeDefinitionTable.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
//
2-
// Copyright (c) .NET Foundation and Contributors
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
34
// Original work from Oleg Rakhmatulin.
4-
// See LICENSE file in the project root for full license information.
5-
//
65

7-
using Mono.Cecil;
8-
using Mono.Collections.Generic;
9-
using nanoFramework.Tools.MetadataProcessor.Core;
10-
using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
116
using System;
127
using System.Collections.Generic;
138
using System.IO;
149
using System.Linq;
10+
using Mono.Cecil;
11+
using Mono.Collections.Generic;
12+
using nanoFramework.Tools.MetadataProcessor.Core;
13+
using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
1514

1615
namespace nanoFramework.Tools.MetadataProcessor
1716
{
@@ -150,7 +149,7 @@ protected override void WriteSingleItem(
150149
writer
151150
);
152151

153-
_context.SignaturesTable.WriteDataType(item, writer, false, true, true);
152+
_context.SignaturesTable.WriteDataTypeForTypeDef(item, writer);
154153

155154
writer.WriteBytes(stream.ToArray());
156155
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
// Original work from Oleg Rakhmatulin.
5+
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.Linq;
9+
using Microsoft.VisualStudio.TestTools.UnitTesting;
10+
using AssemblyDefinition = Mono.Cecil.AssemblyDefinition;
11+
using TypeDefinition = Mono.Cecil.TypeDefinition;
12+
13+
namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Tables
14+
{
15+
[TestClass]
16+
public class nanoSignaturesTableTests
17+
{
18+
[DataRow("System.DateTime", nanoCLR_DataType.DATATYPE_DATETIME)]
19+
[DataRow("System.TimeSpan", nanoCLR_DataType.DATATYPE_TIMESPAN)]
20+
[DataRow("System.String", nanoCLR_DataType.DATATYPE_STRING)]
21+
[DataRow("System.Object", nanoCLR_DataType.DATATYPE_CLASS)]
22+
[DataRow("System.IntPtr", nanoCLR_DataType.DATATYPE_VALUETYPE)]
23+
[DataRow("System.WeakReference", nanoCLR_DataType.DATATYPE_WEAKCLASS)]
24+
[TestMethod]
25+
public void WriteDataTypeForTypeRef_ShouldWriteCorrectDataType(string typeFullName, nanoCLR_DataType dataType)
26+
{
27+
// Arrange
28+
AssemblyDefinition mscorlibAssemblyDefinition = AssemblyDefinition.ReadAssembly(TestObjectHelper.MscorlibFullPath);
29+
30+
nanoTablesContext context = new nanoTablesContext(
31+
mscorlibAssemblyDefinition,
32+
null,
33+
new List<string>(),
34+
null,
35+
false,
36+
false,
37+
true);
38+
39+
TypeDefinition typeToTest = mscorlibAssemblyDefinition.MainModule.Types.First(i => i.FullName == typeFullName);
40+
41+
nanoSignaturesTable table = new nanoSignaturesTable(context);
42+
MemoryStream memoryStream = new MemoryStream();
43+
BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
44+
nanoBinaryWriter writer = nanoBinaryWriter.CreateBigEndianBinaryWriter(binaryWriter);
45+
46+
// Act
47+
table.WriteDataTypeForTypeDef(typeToTest, writer);
48+
49+
// Assert
50+
byte[] expectedBytes = new byte[] { (byte)dataType };
51+
byte[] actualBytes = memoryStream.ToArray();
52+
CollectionAssert.AreEqual(expectedBytes, actualBytes);
53+
}
54+
}
55+
}

MetadataProcessor.Tests/MetadataProcessor.Tests.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
<Compile Include="Core\Tables\nanoMethodDefinitionTableTests.cs" />
6868
<Compile Include="Core\Tables\nanoReferenceTableBaseTests.cs" />
6969
<Compile Include="Core\ClrIntegrationTests.cs" />
70+
<Compile Include="Core\Tables\nanoSignaturesTableTests.cs" />
7071
<Compile Include="Core\Utility\DumperTests.cs" />
7172
<Compile Include="Core\Utility\LoadHintsAssemblyResolverTests.cs" />
7273
<Compile Include="Core\Utility\Crc32Tests.cs" />
@@ -133,4 +134,4 @@
133134
copy /y "$(ProjectDir)StubsGenerationTestNFApp\$(OutDir)\*" "$(TargetDir)\StubsGenerationTestNFApp"
134135
</PreBuildEvent>
135136
</PropertyGroup>
136-
</Project>
137+
</Project>

MetadataProcessor.Tests/TestObjectHelper.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
//
2-
// Copyright (c) .NET Foundation and Contributors
3-
// See LICENSE file in the project root for full license information.
4-
//
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
// Original work from Oleg Rakhmatulin.
55

66
using System;
77
using System.Collections.Generic;
@@ -133,6 +133,16 @@ public static string TestNFClassLibLocation
133133
}
134134
}
135135

136+
public static string MscorlibFullPath
137+
{
138+
get
139+
{
140+
return Path.Combine(
141+
TestNFAppLocation,
142+
"mscorlib.dll");
143+
}
144+
}
145+
136146
public static string NanoClrLocation
137147
{
138148
get

0 commit comments

Comments
 (0)