Skip to content

Commit 30ff529

Browse files
Fixes stubs generation when method has ref parameters (#149)
***NO_CI***
1 parent bc15846 commit 30ff529

File tree

11 files changed

+291
-9
lines changed

11 files changed

+291
-9
lines changed

MetadataProcessor.Core/MetadataProcessor.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,4 @@
7878
</ItemGroup>
7979
<Import Project="..\MetadataProcessor.Shared\MetadataProcessor.Shared.projitems" Label="Shared" />
8080
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
81-
</Project>
81+
</Project>

MetadataProcessor.Shared/Tables/nanoSignaturesTable.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ public void WriteDataType(
282282

283283
if (typeDefinition is TypeSpecification)
284284
{
285-
//Debug.Fail("Gotcha!");
285+
//Debug.Fail("Gotcha!");
286286
}
287287

288288
if (typeDefinition.MetadataType == MetadataType.Class)
@@ -344,14 +344,14 @@ public void WriteDataType(
344344
}
345345
else if (alsoWriteSubType)
346346
{
347-
347+
348348
WriteDataType(array.ElementType, writer, true, expandEnumType, isTypeDefinition);
349349
}
350350

351351
return;
352352
}
353353

354-
if(typeDefinition.IsByReference)
354+
if (typeDefinition.IsByReference)
355355
{
356356
writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_BYREF);
357357

@@ -376,7 +376,7 @@ public void WriteDataType(
376376

377377
writer.WriteByte((byte)genericType.GenericArguments.Count);
378378

379-
foreach(var a in genericType.GenericArguments)
379+
foreach (var a in genericType.GenericArguments)
380380
{
381381
WriteDataType(a, writer, true, expandEnumType, isTypeDefinition);
382382
}
@@ -476,7 +476,7 @@ private byte[] GetSignature(
476476
using (var writer = new BinaryWriter(buffer)) // Only Write(Byte) will be used
477477
{
478478
var binaryWriter = nanoBinaryWriter.CreateBigEndianBinaryWriter(writer);
479-
479+
480480
binaryWriter.WriteByte((byte)interfaces.Count);
481481
foreach (var item in interfaces)
482482
{
@@ -718,7 +718,7 @@ private void WriteSubTypeInfo(TypeReference typeDefinition, nanoBinaryWriter wri
718718
if (typeDefinition is TypeSpecification &&
719719
_context.TypeSpecificationsTable.TryGetTypeReferenceId(typeDefinition, out referenceId))
720720
{
721-
writer.WriteMetadataToken(((uint)referenceId << 2) | 0x02);
721+
writer.WriteMetadataToken(((uint)referenceId << 2) | 0x02);
722722
}
723723
else if (_context.TypeReferencesTable.TryGetTypeReferenceId(typeDefinition, out referenceId))
724724
{

MetadataProcessor.Shared/nanoSkeletonGenerator.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,20 @@ private void GenerateStubs()
153153
foreach (var item in m.Parameters)
154154
{
155155
// get the parameter type
156-
var parameterType = item.ParameterType.ToNativeTypeAsString();
157-
var parameterTypeClr = item.ParameterType.ToCLRTypeAsString();
156+
string parameterType = string.Empty;
157+
string parameterTypeClr = string.Empty;
158+
159+
if (item.ParameterType.IsByReference)
160+
{
161+
// for ref types need an extra step to get the element type
162+
parameterType = item.ParameterType.GetElementType().ToNativeTypeAsString() + "&";
163+
parameterTypeClr = item.ParameterType.GetElementType().ToCLRTypeAsString();
164+
}
165+
else
166+
{
167+
parameterType = item.ParameterType.ToNativeTypeAsString();
168+
parameterTypeClr = item.ParameterType.ToCLRTypeAsString();
169+
}
158170

159171
// compose the function declaration
160172
declaration.Append($"{parameterType} param{parameterIndex.ToString()}, ");
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System;
7+
using System.Collections.Generic;
8+
using System.IO;
9+
using Microsoft.VisualStudio.TestTools.UnitTesting;
10+
using Mono.Cecil;
11+
using nanoFramework.Tools.MetadataProcessor.Core;
12+
13+
namespace nanoFramework.Tools.MetadataProcessor.Tests.Core
14+
{
15+
[TestClass]
16+
public class StubsGenerationTests
17+
{
18+
private const string NativeMethodGenerationDeclaration = @"void NativeMethodGeneration::NativeMethodWithReferenceParameters( uint8_t& param0, uint16_t& param1, HRESULT &hr )
19+
{
20+
21+
(void)param0;
22+
(void)param1;
23+
(void)hr;
24+
25+
26+
////////////////////////////////
27+
// implementation starts here //
28+
29+
30+
// implementation ends here //
31+
////////////////////////////////
32+
33+
34+
}";
35+
36+
[TestMethod]
37+
public void GeneratingStubsFromNFAppTest()
38+
{
39+
var loadHints = new Dictionary<string, string>(StringComparer.Ordinal)
40+
{
41+
["mscorlib"] = Path.Combine(Directory.GetParent(TestObjectHelper.GenerationNFAppFullPath).FullName,
42+
"mscorlib.dll")
43+
};
44+
45+
// class names to exclude from processing
46+
var classNamesToExclude = new List<string>
47+
{
48+
"THIS_NAME_DOES_NOT_EXIST_IN_THE_PROJECT"
49+
};
50+
51+
var fileToParse = TestObjectHelper.GenerationNFAppFullPath;
52+
var fileToCompile = Path.ChangeExtension(fileToParse, "pe");
53+
54+
// get path where stubs will be generated
55+
var stubPath = Path.Combine(
56+
TestObjectHelper.TestExecutionLocation,
57+
"Stubs");
58+
59+
var assemblyDefinition = AssemblyDefinition.ReadAssembly(
60+
fileToParse,
61+
new ReaderParameters { AssemblyResolver = new LoadHintsAssemblyResolver(loadHints) });
62+
63+
var assemblyBuilder = new nanoAssemblyBuilder(assemblyDefinition, classNamesToExclude, false, false);
64+
65+
using (var stream = File.Open(
66+
Path.ChangeExtension(fileToCompile, "tmp"),
67+
FileMode.Create,
68+
FileAccess.ReadWrite))
69+
using (var writer = new BinaryWriter(stream))
70+
{
71+
assemblyBuilder.Write(GetBinaryWriter(writer));
72+
}
73+
74+
// OK to delete tmp PE file
75+
File.Delete(Path.ChangeExtension(fileToCompile, "tmp"));
76+
77+
assemblyBuilder.Minimize();
78+
79+
var tablesContext = assemblyBuilder.TablesContext;
80+
81+
var skeletonGenerator = new nanoSkeletonGenerator(
82+
tablesContext,
83+
stubPath,
84+
"testStubs",
85+
"StubsGenerationTestNFApp",
86+
false,
87+
false);
88+
89+
skeletonGenerator.GenerateSkeleton();
90+
91+
// read generated stub file and look for the function declaration
92+
string generatedFile = File.ReadAllText($"{stubPath}\\StubsGenerationTestNFApp_StubsGenerationTestNFApp_NativeMethodGeneration.cpp");
93+
94+
Assert.IsTrue(generatedFile.Contains(NativeMethodGenerationDeclaration));
95+
96+
Directory.Delete(stubPath, true);
97+
}
98+
99+
private nanoBinaryWriter GetBinaryWriter(
100+
BinaryWriter writer)
101+
{
102+
return nanoBinaryWriter.CreateLittleEndianBinaryWriter(writer);
103+
}
104+
}
105+
}

MetadataProcessor.Tests/MetadataProcessor.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
<Compile Include="Core\Extensions\ParameterDefintionExtensionsTests.cs" />
5757
<Compile Include="Core\Extensions\TypeDefinitionExtensionsTests.cs" />
5858
<Compile Include="Core\Extensions\TypeReferenceExtensionsTests.cs" />
59+
<Compile Include="Core\StubsGenerationTests.cs" />
5960
<Compile Include="Core\Mono.Cecil\CodeWriterTests.cs" />
6061
<Compile Include="Core\Tables\nanoAssemblyReferenceTableTests.cs" />
6162
<Compile Include="Core\Tables\nanoAttributesTableTests.cs" />
@@ -119,8 +120,11 @@
119120
"$(MSBuildBinPath)\msbuild" "$(ProjectDir)mscorlib\nanoFramework.CoreLibrary.sln" -t:Build -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472" /m
120121
"$(MSBuildBinPath)\msbuild" "$(ProjectDir)TestNFClassLibrary\TestNFClassLibrary\TestNFClassLibrary.nfproj" -t:Build -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472"
121122
"$(MSBuildBinPath)\msbuild" "$(ProjectDir)TestNFApp\TestNFApp.nfproj" -t:Build -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472"
123+
"$(MSBuildBinPath)\msbuild" "$(ProjectDir)StubsGenerationTestNFApp\StubsGenerationTestNFApp.nfproj" -t:Build -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472"
122124
mkdir "$(TargetDir)\TestNFApp"
125+
mkdir "$(TargetDir)\StubsGenerationTestNFApp"
123126
copy /y "$(ProjectDir)TestNFApp\$(OutDir)\*" "$(TargetDir)\TestNFApp"
127+
copy /y "$(ProjectDir)StubsGenerationTestNFApp\$(OutDir)\*" "$(TargetDir)\StubsGenerationTestNFApp"
124128
</PreBuildEvent>
125129
</PropertyGroup>
126130
<Target Name="SetNFClrLocation" AfterTargets="Build">
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Runtime.CompilerServices;
7+
8+
namespace StubsGenerationTestNFApp
9+
{
10+
internal class NativeMethodGeneration
11+
{
12+
public void Method()
13+
{
14+
NativeMethod();
15+
16+
byte a = 0;
17+
ushort b = 0;
18+
NativeMethodWithReferenceParameters(ref a, ref b);
19+
}
20+
21+
[MethodImpl(MethodImplOptions.InternalCall)]
22+
private extern void NativeMethod();
23+
24+
[MethodImpl(MethodImplOptions.InternalCall)]
25+
private extern void NativeMethodWithReferenceParameters(ref byte refByteParam, ref ushort refUshortParam);
26+
}
27+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Threading;
7+
8+
namespace StubsGenerationTestNFApp
9+
{
10+
public class Program
11+
{
12+
public static void Main()
13+
{
14+
var nativeMethods = new NativeMethodGeneration();
15+
nativeMethods.Method();
16+
17+
Thread.Sleep(Timeout.Infinite);
18+
}
19+
}
20+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("CSharp.BlankApplication")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("CSharp.BlankApplication")]
13+
[assembly: AssemblyCopyright("Copyright © 2022")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// Version information for an assembly consists of the following four values:
23+
//
24+
// Major Version
25+
// Minor Version
26+
// Build Number
27+
// Revision
28+
//
29+
// You can specify all the values or you can default the Build and Revision Numbers
30+
// by using the '*' as shown below:
31+
// [assembly: AssemblyVersion("1.0.*")]
32+
[assembly: AssemblyVersion("1.0.0.0")]
33+
[assembly: AssemblyNativeVersion("1.0.0.0")]
34+
[assembly: AssemblyFileVersion("1.0.0.0")]
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup Label="Globals">
4+
<NanoFrameworkProjectSystemPath>$(MSBuildExtensionsPath)\nanoFramework\v1.0\</NanoFrameworkProjectSystemPath>
5+
</PropertyGroup>
6+
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props')" />
7+
<PropertyGroup>
8+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
9+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
10+
<ProjectTypeGuids>{11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
11+
<ProjectGuid>06589ff8-1fb2-4513-b2c8-fda351d57bf9</ProjectGuid>
12+
<OutputType>Exe</OutputType>
13+
<AppDesignerFolder>Properties</AppDesignerFolder>
14+
<FileAlignment>512</FileAlignment>
15+
<RootNamespace>StubsGenerationTestNFApp</RootNamespace>
16+
<AssemblyName>StubsGenerationTestNFApp</AssemblyName>
17+
<TargetFrameworkVersion>v1.0</TargetFrameworkVersion>
18+
</PropertyGroup>
19+
<PropertyGroup Label="nanoFramework">
20+
<NFMDP_GENERATE_STUBS>True</NFMDP_GENERATE_STUBS>
21+
</PropertyGroup>
22+
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
23+
<ItemGroup>
24+
<Compile Include="NativeMethodGeneration.cs" />
25+
<Compile Include="Program.cs" />
26+
<Compile Include="Properties\AssemblyInfo.cs" />
27+
</ItemGroup>
28+
<ItemGroup>
29+
<ProjectReference Include="..\mscorlib\nanoFramework.CoreLibrary\CoreLibrary.nfproj" />
30+
</ItemGroup>
31+
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets')" />
32+
<ProjectExtensions>
33+
<ProjectCapabilities>
34+
<ProjectConfigurationsDeclaredAsItems />
35+
</ProjectCapabilities>
36+
</ProjectExtensions>
37+
</Project>

MetadataProcessor.Tests/TestObjectHelper.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public static class TestObjectHelper
2121
private static string _testNFClassLibLocation;
2222
private static string _nanoClrLocation;
2323
private static string _configuration;
24+
private static string _StubsGenerationTestNFAppLocation;
2425

2526
public static nanoTablesContext GetTestNFAppNanoTablesContext()
2627
{
@@ -146,6 +147,43 @@ public static string NanoClrLocation
146147
}
147148
}
148149

150+
public static string GenerationNFAppFullPath
151+
{
152+
get
153+
{
154+
return Path.Combine(
155+
TestExecutionLocation,
156+
"..\\..\\StubsGenerationTestNFApp\\bin",
157+
_configuration,
158+
"StubsGenerationTestNFApp.exe");
159+
}
160+
}
161+
162+
public static string StubsGenerationTestNFAppFullPath
163+
{
164+
get
165+
{
166+
return Path.Combine(
167+
StubsGenerationTestNFAppLocation,
168+
"StubsGenerationTestNFApp.exe");
169+
}
170+
}
171+
172+
public static string StubsGenerationTestNFAppLocation
173+
{
174+
get
175+
{
176+
if (string.IsNullOrEmpty(_StubsGenerationTestNFAppLocation))
177+
{
178+
_StubsGenerationTestNFAppLocation = Path.Combine(
179+
TestExecutionLocation,
180+
"StubsGenerationTestNFApp");
181+
}
182+
183+
return _StubsGenerationTestNFAppLocation;
184+
}
185+
}
186+
149187
public static AssemblyDefinition GetTestNFAppAssemblyDefinition()
150188
{
151189
AssemblyDefinition ret = null;

0 commit comments

Comments
 (0)