Skip to content

Commit b8d3907

Browse files
authored
Add support to process attributes with constructor with multiple parameters (#148)
1 parent 9b306ce commit b8d3907

24 files changed

+730
-56
lines changed

MetadataProcessor.Shared/Tables/nanoSignaturesTable.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public nanoSignaturesTable(nanoTablesContext context)
100100
{
101101
_context = context;
102102

103-
//_verbose = true;
103+
_verbose = context._verbose;
104104
}
105105

106106
/// <summary>
@@ -625,9 +625,24 @@ private void WriteAttributeArgumentValue(
625625
break;
626626
default:
627627
Debug.Fail(dataType.ToString());
628-
break;
628+
throw new ArgumentException($"Failed to generate signature for CustomAttribute. Unsupported type: {argument.Type.FullName}.");
629629
}
630630
}
631+
632+
if (argument.Type.IsArray && argument.Type.GetElementType().FullName == "System.Object")
633+
{
634+
var paramCollection = (CustomAttributeArgument[])argument.Value;
635+
636+
// add count of array elements that will follow
637+
writer.Write((byte)paramCollection.Length);
638+
639+
// now add parameters as usual
640+
foreach (var attributeArgument in paramCollection)
641+
{
642+
WriteAttributeArgumentValue(writer, (CustomAttributeArgument)attributeArgument.Value);
643+
}
644+
}
645+
631646
if (argument.Type.FullName == "System.Type")
632647
{
633648
writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_STRING);

MetadataProcessor.Shared/Tables/nanoTablesContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ namespace nanoFramework.Tools.MetadataProcessor
1313
{
1414
public sealed class nanoTablesContext
1515
{
16+
internal readonly bool _verbose;
17+
internal readonly bool _isCoreLibrary;
18+
1619
internal static HashSet<string> IgnoringAttributes { get; } = new HashSet<string>(StringComparer.Ordinal)
1720
{
1821
// Assembly-level attributes
@@ -73,6 +76,8 @@ public nanoTablesContext(
7376
AssemblyDefinition = assemblyDefinition;
7477

7578
ClassNamesToExclude = classNamesToExclude;
79+
_verbose = verbose;
80+
_isCoreLibrary = isCoreLibrary;
7681

7782
// check CustomAttributes against list of classes to exclude
7883
foreach (var item in assemblyDefinition.CustomAttributes)

MetadataProcessor.Shared/nanoDumperGenerator.cs

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ private void DumpCustomAttributes(DumpAllTable dumpTable)
7575
{
7676
foreach (var value in ma.CustomAttributes[0].ConstructorArguments)
7777
{
78-
attribute.FixedArgs.Add(BuildFixedArgsAttribute(value));
78+
attribute.FixedArgs.AddRange(BuildFixedArgsAttribute(value));
7979
}
8080
}
8181

@@ -98,45 +98,39 @@ private void DumpCustomAttributes(DumpAllTable dumpTable)
9898
{
9999
foreach (var value in fa.CustomAttributes[0].ConstructorArguments)
100100
{
101-
attribute.FixedArgs.Add(BuildFixedArgsAttribute(value));
101+
attribute.FixedArgs.AddRange(BuildFixedArgsAttribute(value));
102102
}
103103
}
104104

105105
dumpTable.Attributes.Add(attribute);
106106
}
107107
}
108+
}
109+
}
108110

109-
var attribute1 = new AttributeCustom()
110-
{
111-
Name = a.Module.Assembly.Name.Name,
112-
ReferenceId = a.MetadataToken.ToInt32().ToString("x8"),
113-
TypeToken = a.CustomAttributes[0].Constructor.MetadataToken.ToInt32().ToString("x8")
114-
};
111+
private List<AttFixedArgs> BuildFixedArgsAttribute(CustomAttributeArgument value)
112+
{
113+
if (value.Type.IsArray && value.Type.GetElementType().FullName == "System.Object")
114+
{
115+
var attArgs = new List<AttFixedArgs>();
115116

116-
if (a.CustomAttributes[0].HasConstructorArguments)
117+
foreach (var attributeArgument in (CustomAttributeArgument[])value.Value)
117118
{
118-
foreach (var value in a.CustomAttributes[0].ConstructorArguments)
119-
{
120-
attribute1.FixedArgs.Add(BuildFixedArgsAttribute(value));
121-
}
119+
attArgs.AddRange(BuildFixedArgsAttribute((CustomAttributeArgument)attributeArgument.Value));
122120
}
123121

124-
dumpTable.Attributes.Add(attribute1);
122+
return attArgs;
125123
}
126-
}
127124

128-
private AttFixedArgs BuildFixedArgsAttribute(CustomAttributeArgument value)
129-
{
130125
var serializationType = value.Type.ToSerializationType();
131126

132127
var newArg = new AttFixedArgs()
133128
{
134129
Options = ((byte)serializationType).ToString("X2"),
135-
Numeric = 0.ToString("X16"),
136130
Text = "",
137131
};
138132

139-
switch(serializationType)
133+
switch (serializationType)
140134
{
141135
case nanoSerializationType.ELEMENT_TYPE_BOOLEAN:
142136
newArg.Numeric = ((bool)value.Value) ? 1.ToString("X16") : 0.ToString("X16");
@@ -146,12 +140,48 @@ private AttFixedArgs BuildFixedArgsAttribute(CustomAttributeArgument value)
146140
newArg.Text = (string)value.Value;
147141
break;
148142

149-
default:
143+
case nanoSerializationType.ELEMENT_TYPE_OBJECT:
144+
newArg.Text = (string)value.Value;
145+
break;
146+
147+
case nanoSerializationType.ELEMENT_TYPE_I1:
148+
newArg.Numeric = ((sbyte)value.Value).ToString("X16");
149+
break;
150+
151+
case nanoSerializationType.ELEMENT_TYPE_I2:
152+
newArg.Numeric = ((short)value.Value).ToString("X16");
153+
break;
154+
155+
case nanoSerializationType.ELEMENT_TYPE_I4:
150156
newArg.Numeric = ((int)value.Value).ToString("X16");
151157
break;
158+
159+
case nanoSerializationType.ELEMENT_TYPE_I8:
160+
newArg.Numeric = ((long)value.Value).ToString("X16");
161+
break;
162+
163+
case nanoSerializationType.ELEMENT_TYPE_U1:
164+
newArg.Numeric = ((byte)value.Value).ToString("X16");
165+
break;
166+
167+
case nanoSerializationType.ELEMENT_TYPE_U2:
168+
newArg.Numeric = ((ushort)value.Value).ToString("X16");
169+
break;
170+
171+
case nanoSerializationType.ELEMENT_TYPE_U4:
172+
newArg.Numeric = ((uint)value.Value).ToString("X16");
173+
break;
174+
175+
case nanoSerializationType.ELEMENT_TYPE_U8:
176+
newArg.Numeric = ((ulong)value.Value).ToString("X16");
177+
break;
178+
179+
default:
180+
newArg.Text = value.Value.ToString();
181+
break;
152182
}
153183

154-
return newArg;
184+
return new List<AttFixedArgs>() { newArg };
155185
}
156186

157187
private void DumpUserStrings(DumpAllTable dumpTable)

MetadataProcessor.Tests/Core/ClrIntegrationTests.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class ClrIntegrationTests
1818
[TestMethod]
1919
public void RunBCLTest()
2020
{
21-
var workingDirectory = Path.GetDirectoryName(TestObjectHelper.TestNFAppLocation);
21+
var workingDirectory = TestObjectHelper.TestNFAppLocation;
2222
var mscorlibLocation = Path.Combine(workingDirectory, "mscorlib.pe");
2323

2424
// prepare the process start of the WIN32 nanoCLR
@@ -59,10 +59,10 @@ public void RunTestNFAppTest()
5959
// 5 seconds
6060
int runTimeout = 5000;
6161

62-
var workingDirectory = Path.GetDirectoryName(TestObjectHelper.TestNFAppLocation);
62+
var workingDirectory = TestObjectHelper.TestNFAppLocation;
6363
var mscorlibLocation = Path.Combine(workingDirectory, "mscorlib.pe");
64-
var nfTestAppLocation = TestObjectHelper.TestNFAppLocation.Replace("exe", "pe");
65-
var nfTestClassLibLocation = TestObjectHelper.TestNFClassLibLocation.Replace("dll", "pe");
64+
var nfTestAppLocation = TestObjectHelper.TestNFAppFullPath.Replace("exe", "pe");
65+
var nfTestClassLibLocation = TestObjectHelper.TestNFClassLibFullPath.Replace("dll", "pe");
6666

6767
// prepare the process start of the WIN32 nanoCLR
6868
Process nanoClr = new Process();
@@ -84,7 +84,11 @@ public void RunTestNFAppTest()
8484
};
8585

8686
// launch nanoCLR
87-
if (!nanoClr.Start())
87+
if (nanoClr.Start())
88+
{
89+
Console.WriteLine($"Running nanoCLR Win32 @ '{TestObjectHelper.NanoClrLocation}'");
90+
}
91+
else
8892
{
8993
Assert.Fail("Failed to start nanoCLR Win32");
9094
}
@@ -125,14 +129,15 @@ public void RunTestNFAppTest()
125129
// wait for exit, no worries about the outcome
126130
nanoClr.WaitForExit(runTimeout);
127131

132+
var outputOfTest = output.ToString();
128133

129134
// look for standard messages
130-
Assert.IsTrue(output.ToString().Contains("Ready."), "Failed to find READY message.");
131-
Assert.IsTrue(output.ToString().Contains("Done."), "Failed to find DONE message.");
132-
Assert.IsTrue(output.ToString().Contains("Exiting."), "Failed to find EXITING message.");
135+
Assert.IsTrue(outputOfTest.Contains("Ready."), $"Failed to find READY message.{Environment.NewLine}Output is:{Environment.NewLine}{outputOfTest}");
136+
Assert.IsTrue(outputOfTest.Contains("Done."), $"Failed to find DONE message.{Environment.NewLine}Output is:{Environment.NewLine}{outputOfTest}");
137+
Assert.IsTrue(outputOfTest.Contains("Exiting."), $"Failed to find EXITING message.{Environment.NewLine}Output is:{Environment.NewLine}{outputOfTest}");
133138

134139
// look for any exceptions
135-
Assert.IsFalse(output.ToString().Contains("++++ Exception "), "Exception thrown by TestNFApp application.");
140+
Assert.IsFalse(outputOfTest.Contains("++++ Exception "), $"Exception thrown by TestNFApp application.{Environment.NewLine}Output is:{Environment.NewLine}{outputOfTest}");
136141
}
137142
finally
138143
{

MetadataProcessor.Tests/Core/Mono.Cecil/CodeWriterTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ public void WriteMethodBodyIntegrationTest()
440440
var expectedBytesWritten = new byte[] { 0x16, 0x0A, 0x03, 0x04, 0x58, 0x0A, 0xDE, 0x16, 0x0B, 0x72, 0x48, 0x01, 0x07, 0x73, 0x0C, 0x80, 0x0C, 0x08, 0x6F, 0x0D, 0x80, 0x0A, 0xDE, 0x00, 0x06, 0x2A, 0x00, 0x00, 0x0F, 0x80, 0x02, 0x00, 0x08, 0x00, 0x08, 0x00, 0x1E, 0x00, 0x01 };
441441
#endif
442442

443-
CollectionAssert.AreEqual(expectedBytesWritten, bytesWritten, BitConverter.ToString(bytesWritten));
443+
Assert.AreEqual(expectedBytesWritten.Length, bytesWritten.Length, "Method body length differs.");
444444
}
445445
}
446446
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
using Microsoft.VisualStudio.TestTools.UnitTesting;
7+
using nanoFramework.Tools.MetadataProcessor.Core;
8+
using System;
9+
using System.IO;
10+
11+
namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Utility
12+
{
13+
[TestClass]
14+
public class DumperTests
15+
{
16+
[TestMethod]
17+
public void DumpAssemblyTest()
18+
{
19+
var nanoTablesContext = TestObjectHelper.GetTestNFAppNanoTablesContext();
20+
21+
var fileNameBase = $"{DateTime.UtcNow.ToShortDateString()}_{DateTime.UtcNow.ToLongTimeString()}";
22+
fileNameBase = fileNameBase.Replace(':', '_').Replace('/', '_');
23+
24+
var dumpFileName = Path.Combine(TestObjectHelper.TestExecutionLocation, $"{fileNameBase}_dump.txt");
25+
26+
nanoDumperGenerator dumper = new nanoDumperGenerator(
27+
nanoTablesContext,
28+
dumpFileName);
29+
dumper.DumpAll();
30+
31+
// read back file
32+
var dumpFileContent = File.ReadAllText(dumpFileName);
33+
34+
// search for bits
35+
36+
// AssemblyRefs
37+
Assert.IsTrue(dumpFileContent.Contains("AssemblyRefProps [23000001]: Flags: 00000000 'mscorlib'"));
38+
Assert.IsTrue(dumpFileContent.Contains("AssemblyRefProps [23000002]: Flags: 00000000 'TestNFClassLibrary'"));
39+
40+
// TypeRefs
41+
Assert.IsTrue(dumpFileContent.Contains("TypeRefProps [01000001]: Scope: 23000001 'System.Diagnostics.DebuggableAttribute'"));
42+
Assert.IsTrue(dumpFileContent.Contains(": Scope: 23000002 'TestNFClassLibrary.ClassOnAnotherAssembly'"));
43+
44+
Assert.IsTrue(dumpFileContent.Contains(": Flags: 00001001 Extends: 0100000d Enclosed: 02000000 'TestNFApp.DummyCustomAttribute1'"));
45+
46+
Assert.IsTrue(dumpFileContent.Contains(": Flags: 00001001 Extends: 0100000d Enclosed: 02000000 'TestNFApp.DummyCustomAttribute2'"));
47+
48+
Assert.IsTrue(dumpFileContent.Contains(": Flags: 00000061 Extends: 01000000 Enclosed: 02000000 'TestNFApp.IOneClassOverAll'"));
49+
Assert.IsTrue(dumpFileContent.Contains(": Flags: 000007c6 Impl: 00000000 RVA: 00000000 'get_DummyProperty' [I4( )]"));
50+
Assert.IsTrue(dumpFileContent.Contains(": Flags: 000007c6 Impl: 00000000 RVA: 00000000 'set_DummyProperty' [VOID( I4 )]"));
51+
Assert.IsTrue(dumpFileContent.Contains(": Flags: 000003c6 Impl: 00000000 RVA: 00000000 'DummyMethod' [VOID( )]"));
52+
53+
Assert.IsTrue(dumpFileContent.Contains("Enclosed: 02000000 'TestNFApp.OneClassOverAll'"));
54+
Assert.IsTrue(dumpFileContent.Contains(": Attr: 00000001 Flags: 00000001 'dummyField' [STRING]"));
55+
Assert.IsTrue(dumpFileContent.Contains(": Attr: 00000001 Flags: 00000001 '<DummyProperty>k__BackingField' [I4]"));
56+
Assert.IsTrue(dumpFileContent.Contains(": Flags: 00000086 Impl: 00000000 RVA: 00000000 'DummyExternMethod' [VOID( )]"));
57+
58+
Assert.IsTrue(dumpFileContent.Contains("'TestNFApp.Program'"));
59+
60+
Assert.IsTrue(dumpFileContent.Contains("'SubClass'"));
61+
62+
// UserStrings
63+
Assert.IsTrue(dumpFileContent.Contains(": 'TestNFClassLibrary'"));
64+
Assert.IsTrue(dumpFileContent.Contains(": 'get_DummyProperty'"));
65+
Assert.IsTrue(dumpFileContent.Contains(": 'blabla'"));
66+
}
67+
}
68+
}

MetadataProcessor.Tests/MetadataProcessor.Tests.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
<NuGetPackageImportStamp>
2121
</NuGetPackageImportStamp>
2222
<TargetFrameworkProfile />
23-
<NF_MDP_MSBUILDTASK_PATH>$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472\*</NF_MDP_MSBUILDTASK_PATH>
2423
</PropertyGroup>
2524
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
2625
<DebugSymbols>true</DebugSymbols>
@@ -62,12 +61,14 @@
6261
<Compile Include="Core\Tables\nanoAttributesTableTests.cs" />
6362
<Compile Include="Core\Tables\nanoReferenceTableBaseTests.cs" />
6463
<Compile Include="Core\ClrIntegrationTests.cs" />
64+
<Compile Include="Core\Utility\DumperTests.cs" />
6565
<Compile Include="Core\Utility\LoadHintsAssemblyResolverTests.cs" />
6666
<Compile Include="Core\Utility\Crc32Tests.cs" />
6767
<Compile Include="Core\Utility\nanoBitmapProcessorTests.cs" />
6868
<Compile Include="Core\Utility\nanoDependencyGeneratorWriterTests.cs" />
6969
<Compile Include="Core\Utility\nanoStringsConstantsTests.cs" />
7070
<Compile Include="Core\Utility\NativeMethodsCrcTests.cs" />
71+
<Compile Include="MsbuildTask\MsbuildTaskTests.cs" />
7172
<Compile Include="Properties\AssemblyInfo.cs" />
7273
<Compile Include="TestObjectHelper.cs" />
7374
<Compile Include="TestPreprocessedFiles.cs" />
@@ -105,7 +106,7 @@
105106
<Version>2.2.8</Version>
106107
</PackageReference>
107108
<PackageReference Include="nanoFramework.nanoCLR.Win32" GeneratePathProperty="true">
108-
<Version>1.7.4-preview.39</Version>
109+
<Version>1.7.4-preview.42</Version>
109110
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
110111
<PrivateAssets>all</PrivateAssets>
111112
</PackageReference>

0 commit comments

Comments
 (0)