Skip to content

Commit 01135b2

Browse files
authored
Merge pull request #69 from Ted-Jin-Lab/development
🐛Cpp throw fix.
2 parents c2e77bc + c170bfd commit 01135b2

8 files changed

Lines changed: 111 additions & 78 deletions

File tree

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project>
33
<PropertyGroup>
4-
<Version>2025.11.24.0</Version>
4+
<Version>2025.11.24.1</Version>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<LangVersion>preview</LangVersion>

Tests/TedToolkit.Console/FunctionPointer2.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ unsafe partial class FunctionPointer2
44
{
55
public void Test2(int value, FunctionPointer2_Test_method_Delegate method1)
66
{
7-
SafeRun(loader =>
8-
{
9-
var method = (delegate* unmanaged[Cdecl]<FunctionPointer2.Data*, int, FunctionPointer2_Test_method_Delegate, global::System.IntPtr> )loader.GetFunctionPointer("FunctionPointer2_Test");
10-
return method(Ptr, value, method1);
11-
});
7+
var __method =
8+
(delegate* unmanaged[Cdecl]<FunctionPointer2.Data**, global::System.IntPtr>)Loader.GetFunctionPointer(
9+
"FunctionPointer2_Create_0");
10+
fixed (Data** ptr = &Ptr)
11+
ThrowIfError(__method(ptr));
1212
}
1313
}

Tests/TedToolkit.Console/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using TedToolkit.Assertions.FluentValidation;
1010
using TedToolkit.Console;
1111
using TedToolkit.Console.Wrapper;
12+
using TedToolkit.CppInteropGen;
1213
using TedToolkit.QuantExtensions;
1314
using TedToolkit.ValidResults;
1415
using UnitsNet;
@@ -31,6 +32,8 @@
3132
Console.WriteLine(length);
3233
unsafe
3334
{
35+
var hello = 0;
36+
double x = *(double*)&hello;
3437
var ptr = (double*)&length;
3538
Console.WriteLine(*ptr);
3639

src/analyzers/TedToolkit.CppInteropGen.SourceGenerator/BaseParameterGenerator.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@ public enum ParameterType : byte
1818
public abstract bool IsRefOrOut { get; }
1919
public abstract TypeSyntax PublicType { get; }
2020
public abstract TypeSyntax InnerType { get; }
21+
public abstract TypeSyntax InnerCppType{ get; }
2122
public abstract ParameterSyntax GenerateParameter();
2223
public abstract IEnumerable<DelegateDeclarationSyntax> GenerateDelegates();
2324
public abstract IEnumerable<LocalDeclarationStatementSyntax> GenerateLocalDeclaration();
2425
public abstract ArgumentSyntax GenerateArgument();
2526
public abstract ExpressionStatementSyntax GenerateAssignment();
2627

2728
public static IEnumerable<BaseParameterGenerator> GenerateParameters(string methodName, string parameterNames,
28-
string[] allClassNames)
29+
string[] allClassNames, Dictionary<string, string> parameterTypeReplace)
2930
{
3031
var funcPtrRegex = new Regex(
3132
@"(?<retType>\w[\w\s\*&]*)\s*\(\*(?<name>\w+)\)\s*\((?<args>[^\)]*)\)"
@@ -38,11 +39,11 @@ public static IEnumerable<BaseParameterGenerator> GenerateParameters(string meth
3839
var name = match.Groups["name"].Value;
3940
var args = match.Groups["args"].Value;
4041
var retType = match.Groups["retType"].Value;
41-
yield return new FunctionPointParameterGenerator(methodName, name, retType, args, allClassNames);
42+
yield return new FunctionPointParameterGenerator(methodName, name, retType, args, allClassNames, parameterTypeReplace);
4243
}
4344
else
4445
{
45-
yield return new ParameterGenerator(parameterName, allClassNames);
46+
yield return new ParameterGenerator(parameterName, allClassNames, parameterTypeReplace);
4647
}
4748
}
4849
}
@@ -74,7 +75,7 @@ private static IEnumerable<string> GetParameterNames(string input)
7475
yield return input.Substring(start).Trim();
7576
}
7677

77-
protected static string GetTypeNameFromCpp(string typeName, string[] allClassNames)
78+
protected internal static string GetTypeNameFromCpp(string typeName, string[] allClassNames)
7879
{
7980
return typeName switch
8081
{

src/analyzers/TedToolkit.CppInteropGen.SourceGenerator/CppClassGenerator.cs

Lines changed: 67 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public CppClassGenerator(SourceText text, string className, Config config, strin
2626
List<CMethodGenerator> methods = [];
2727
StringBuilder? builder = null;
2828

29+
Dictionary<string, string> typeDefinitions = [];
30+
2931
foreach (var line in text.Lines)
3032
{
3133
var lineText = line.ToString().Trim();
@@ -46,6 +48,25 @@ public CppClassGenerator(SourceText text, string className, Config config, strin
4648
{
4749
builder.Append(lineText.Trim());
4850
}
51+
else if (IsStartWith(ref lineText, "typedef"))
52+
{
53+
var types = lineText.Substring(0, lineText.Length - 1).Split(' ');
54+
if (types.Length is not 2) continue;
55+
var replacedName = BaseParameterGenerator.GetTypeNameFromCpp(types[0], []);
56+
if (replacedName
57+
is not "sbyte" and not "byte"
58+
and not "short" and not "ushort"
59+
and not "int" and not "uint"
60+
and not "long" and not "ulong"
61+
and not "global::System.IntPtr" and not "global::System.UIntPtr"
62+
and not "char"
63+
and not "float" and not "double")
64+
{
65+
continue;
66+
}
67+
68+
typeDefinitions[types[1]] = replacedName;
69+
}
4970
}
5071

5172
if (builder is not null) CheckBuilder(builder);
@@ -60,7 +81,7 @@ void CheckBuilder(StringBuilder stringBuilder)
6081
var index = str.IndexOf('{');
6182
if (index < 0) return;
6283
var methodDeclare = str.Substring(0, index);
63-
methods.Add(new CMethodGenerator(methodDeclare, className, privateIt, allClassNames));
84+
methods.Add(new CMethodGenerator(methodDeclare, className, privateIt, allClassNames, typeDefinitions));
6485
}
6586
}
6687

@@ -81,7 +102,8 @@ public ClassDeclarationSyntax Generate()
81102
]))
82103
.WithAttributeLists([GeneratedCodeAttribute(typeof(CppClassGenerator))])
83104
.WithModifiers(
84-
TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.ReadOnlyKeyword))),
105+
TokenList(Token(_config.IsInternal ? SyntaxKind.InternalKeyword : SyntaxKind.PublicKeyword),
106+
Token(SyntaxKind.ReadOnlyKeyword))),
85107

86108
StructDeclaration("Data")
87109
.WithAttributeLists(
@@ -164,7 +186,7 @@ private class CMethodGenerator
164186
private readonly IReadOnlyList<BaseParameterGenerator> _parameters;
165187

166188
public CMethodGenerator(string methodDeclare, string className, bool isPrivate,
167-
string[] allClassesName)
189+
string[] allClassesName, Dictionary<string, string> parameterTypeReplace)
168190
{
169191
_className = className;
170192
var startIndex = methodDeclare.IndexOf('(');
@@ -174,7 +196,8 @@ public CMethodGenerator(string methodDeclare, string className, bool isPrivate,
174196
var endIndex = methodDeclare.LastIndexOf(')');
175197

176198
_parameters = BaseParameterGenerator.GenerateParameters(_methodName,
177-
methodDeclare.Substring(startIndex + 1, endIndex - startIndex - 1), allClassesName).ToArray();
199+
methodDeclare.Substring(startIndex + 1, endIndex - startIndex - 1), allClassesName,
200+
parameterTypeReplace).ToArray();
178201

179202
_isPrivate = isPrivate || _parameters.Any(p => p.HasHandle);
180203
}
@@ -191,21 +214,23 @@ public IEnumerable<MemberDeclarationSyntax> Generate()
191214
.._parameters.Take(_parameters.Count - 1).Select(p => p.GenerateParameter())
192215
]))
193216
.WithBody(Block(
194-
GetRunMethod(Block(
195-
GetFunctionPointer(_parameters.Select(p => FunctionPointerParameter(p.InnerType))),
196-
FixedStatement(VariableDeclaration(PointerType(PointerType(IdentifierName("Data"))))
197-
.WithVariables([
198-
VariableDeclarator(Identifier("ptr"))
199-
.WithInitializer(EqualsValueClause(PrefixUnaryExpression(
200-
SyntaxKind.AddressOfExpression, IdentifierName("Ptr"))))
201-
]),
202-
ReturnStatement(InvocationExpression(IdentifierName("__method"))
203-
.WithArgumentList(ArgumentList(
204-
[
205-
.._parameters.Take(_parameters.Count - 1).Select(p => p.GenerateArgument()),
206-
Argument(IdentifierName("ptr"))
207-
]))))
208-
))));
217+
GetFunctionPointer(_parameters.Select(p => FunctionPointerParameter(p.InnerType))),
218+
FixedStatement(VariableDeclaration(PointerType(PointerType(IdentifierName("Data"))))
219+
.WithVariables([
220+
VariableDeclarator(Identifier("ptr"))
221+
.WithInitializer(EqualsValueClause(PrefixUnaryExpression(
222+
SyntaxKind.AddressOfExpression, IdentifierName("Ptr"))))
223+
]),
224+
ExpressionStatement(InvocationExpression(IdentifierName("ThrowIfError"))
225+
.WithArgumentList(ArgumentList([
226+
Argument(InvocationExpression(IdentifierName("__method"))
227+
.WithArgumentList(ArgumentList(
228+
[
229+
.._parameters.Take(_parameters.Count - 1).Select(p => p.GenerateArgument()),
230+
Argument(IdentifierName("ptr"))
231+
])))
232+
]))))
233+
));
209234
yield break;
210235
}
211236

@@ -215,14 +240,16 @@ public IEnumerable<MemberDeclarationSyntax> Generate()
215240
.WithModifiers(TokenList(Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.OverrideKeyword)))
216241
.WithAttributeLists([GeneratedCodeAttribute(typeof(CMethodGenerator))])
217242
.WithBody(Block(
218-
GetRunMethod(Block(
219-
GetFunctionPointer(_parameters.Select(p => FunctionPointerParameter(p.InnerType))),
220-
ReturnStatement(InvocationExpression(IdentifierName("__method"))
221-
.WithArgumentList(ArgumentList(
222-
[
223-
Argument(IdentifierName("Ptr"))
224-
])))
225-
))));
243+
GetFunctionPointer(_parameters.Select(p => FunctionPointerParameter(p.InnerType))),
244+
ExpressionStatement(InvocationExpression(IdentifierName("ThrowIfError"))
245+
.WithArgumentList(ArgumentList([
246+
Argument(InvocationExpression(IdentifierName("__method"))
247+
.WithArgumentList(ArgumentList(
248+
[
249+
Argument(IdentifierName("Ptr")),
250+
])))
251+
])))
252+
));
226253
yield break;
227254
}
228255

@@ -242,28 +269,22 @@ public IEnumerable<MemberDeclarationSyntax> Generate()
242269
.WithBody(Block((StatementSyntax[])
243270
[
244271
.._parameters.Skip(1).Where(p => p.IsRefOrOut).SelectMany(p => p.GenerateLocalDeclaration()),
245-
GetRunMethod(Block(
246-
GetFunctionPointer(_parameters.Select(p => FunctionPointerParameter(p.InnerType))),
247-
ReturnStatement(InvocationExpression(IdentifierName("__method"))
248-
.WithArgumentList(ArgumentList(
249-
[
250-
Argument(IdentifierName("Ptr")),
251-
.._parameters.Skip(1).Select(p => p.GenerateArgument())
252-
]))))),
272+
273+
GetFunctionPointer(_parameters.Select((p, i) =>
274+
FunctionPointerParameter(i == 0 ? p.InnerType : p.InnerCppType))),
275+
ExpressionStatement(InvocationExpression(IdentifierName("ThrowIfError"))
276+
.WithArgumentList(ArgumentList([
277+
Argument(InvocationExpression(IdentifierName("__method"))
278+
.WithArgumentList(ArgumentList(
279+
[
280+
Argument(IdentifierName("Ptr")),
281+
.._parameters.Skip(1).Select(p => p.GenerateArgument())
282+
])))
283+
]))),
253284
.._parameters.Skip(1).Where(p => p.IsRefOrOut).Select(p => p.GenerateAssignment())
254285
]));
255286
yield break;
256287

257-
ExpressionStatementSyntax GetRunMethod(BlockSyntax block)
258-
{
259-
return ExpressionStatement(InvocationExpression(IdentifierName("SafeRun"))
260-
.WithArgumentList(ArgumentList(
261-
[
262-
Argument(SimpleLambdaExpression(Parameter(Identifier("loader")))
263-
.WithBlock(block))
264-
])));
265-
}
266-
267288
LocalDeclarationStatementSyntax GetFunctionPointer(IEnumerable<FunctionPointerParameterSyntax> parameters)
268289
{
269290
return LocalDeclarationStatement(VariableDeclaration(IdentifierName("var"))
@@ -283,9 +304,7 @@ LocalDeclarationStatementSyntax GetFunctionPointer(IEnumerable<FunctionPointerPa
283304
..parameters,
284305
FunctionPointerParameter(IdentifierName("global::System.IntPtr"))
285306
])),
286-
InvocationExpression(MemberAccessExpression(
287-
SyntaxKind.SimpleMemberAccessExpression,
288-
IdentifierName("loader"), IdentifierName("GetFunctionPointer")))
307+
InvocationExpression( IdentifierName("GetFunctionPointer"))
289308
.WithArgumentList(ArgumentList(
290309
[
291310
Argument(LiteralExpression(SyntaxKind.StringLiteralExpression,

src/analyzers/TedToolkit.CppInteropGen.SourceGenerator/FunctionPointParameterGenerator.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ namespace TedToolkit.CppInteropGen.SourceGenerator;
99
using static SyntaxExtensions;
1010
using static SyntaxFactory;
1111

12-
public class FunctionPointParameterGenerator(string methodName, string name, string returnType, string args, string[] allClassNames)
12+
public class FunctionPointParameterGenerator(string methodName, string name, string returnType, string args, string[] allClassNames, Dictionary<string, string> parameterTypeReplace)
1313
: BaseParameterGenerator
1414
{
1515
private readonly IReadOnlyList<BaseParameterGenerator> _parameters =
16-
GenerateParameters(methodName + "_" + name, args, allClassNames).ToArray();
16+
GenerateParameters(methodName + "_" + name, args, allClassNames, parameterTypeReplace).ToArray();
1717

18-
private readonly ParameterGenerator _return = new(returnType, allClassNames);
18+
private readonly ParameterGenerator _return = new(returnType, allClassNames, parameterTypeReplace);
1919
private readonly string _delegateName = methodName + "_" + name + "_Delegate";
2020
public override string Name { get; } = name;
2121
public override bool HasHandle => false;
@@ -24,6 +24,7 @@ public class FunctionPointParameterGenerator(string methodName, string name, str
2424
public override TypeSyntax PublicType => IdentifierName(_delegateName);
2525

2626
public override TypeSyntax InnerType => IdentifierName(_delegateName);
27+
public override TypeSyntax InnerCppType => IdentifierName(_delegateName);
2728

2829
public override ParameterSyntax GenerateParameter()
2930
{
@@ -52,7 +53,7 @@ public override IEnumerable<DelegateDeclarationSyntax> GenerateDelegates()
5253
.WithParameterList(ParameterList(
5354
[
5455
.._parameters.Select(i =>
55-
Parameter(Identifier(i.Name)).WithType(i.InnerType)),
56+
Parameter(Identifier(i.Name)).WithType(i.InnerCppType)),
5657
]));
5758
}
5859

src/analyzers/TedToolkit.CppInteropGen.SourceGenerator/ParameterGenerator.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
1-
using System.Text;
2-
using Microsoft.CodeAnalysis.CSharp;
1+
using Microsoft.CodeAnalysis.CSharp;
32
using Microsoft.CodeAnalysis.CSharp.Syntax;
4-
using Microsoft.CodeAnalysis.Text;
53
using SyntaxExtensions = TedToolkit.RoslynHelper.Extensions.SyntaxExtensions;
64

75
namespace TedToolkit.CppInteropGen.SourceGenerator;
86

9-
using static SyntaxExtensions;
107
using static SyntaxFactory;
118

129
public sealed class ParameterGenerator : BaseParameterGenerator
1310
{
1411
private readonly int _ptrCount;
1512
private readonly string _rawTypeName;
13+
private readonly string _cppTypeName;
1614
private readonly ParameterType _type;
1715
public override string Name { get; }
1816

19-
public ParameterGenerator(string parameterString, string[] allClassNames)
17+
public ParameterGenerator(string parameterString, string[] allClassNames,
18+
Dictionary<string, string> parameterTypeReplace)
2019
{
2120
var cleanedString = parameterString
2221
.Replace("const", string.Empty)
@@ -29,6 +28,9 @@ public ParameterGenerator(string parameterString, string[] allClassNames)
2928
var typeName = beautifulStrings.First(s => !string.IsNullOrEmpty(s));
3029
Name = beautifulStrings.Last(s => !string.IsNullOrEmpty(s));
3130
_rawTypeName = GetTypeNameFromCpp(typeName, allClassNames);
31+
_cppTypeName = parameterTypeReplace.TryGetValue(typeName, out var replaceName)
32+
? replaceName
33+
: _rawTypeName;
3234
_type = CheckType();
3335
return;
3436

@@ -85,11 +87,19 @@ public override IEnumerable<DelegateDeclarationSyntax> GenerateDelegates()
8587
}
8688

8789
public override TypeSyntax InnerType => IdentifierName(_rawTypeName + new string('*', _ptrCount));
90+
public override TypeSyntax InnerCppType => IdentifierName(_cppTypeName + new string('*', _ptrCount));
8891

8992
public override ArgumentSyntax GenerateArgument()
9093
{
9194
var name = IsData && _type is not ParameterType.Out ? Name + ".Ptr" : Name;
9295
if (_type is ParameterType.Out or ParameterType.Ref) name = "__" + name;
96+
if (_rawTypeName != _cppTypeName)
97+
{
98+
return Argument(PrefixUnaryExpression(SyntaxKind.PointerIndirectionExpression,
99+
CastExpression(PointerType(IdentifierName(_cppTypeName)),
100+
PrefixUnaryExpression(SyntaxKind.AddressOfExpression, IdentifierName(name)))));
101+
}
102+
93103
return Argument(IdentifierName(name));
94104
}
95105

src/libraries/TedToolkit.CppInteropGen/CppObject.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,19 @@ void IDisposable.Dispose()
5757
Delete();
5858
}
5959

60+
/// <summary>
61+
/// Get the Method Pointer.
62+
/// </summary>
63+
protected IntPtr GetFunctionPointer(string name) =>
64+
NativeFunctionLoader.GetLoader(FileFullPath).GetFunctionPointer(name);
65+
6066
[DebuggerStepThrough]
61-
protected void SafeRun(Func<NativeFunctionLoader, IntPtr> func)
67+
protected unsafe void ThrowIfError(IntPtr errorPtr)
6268
{
63-
var loader = NativeFunctionLoader.GetLoader(FileFullPath);
64-
var errorPtr = func(loader);
6569
if (errorPtr == IntPtr.Zero) return;
66-
throw new CppException(GetStringFromIntPtr(errorPtr, loader));
67-
68-
static unsafe string GetStringFromIntPtr(IntPtr errorPtr, NativeFunctionLoader loader)
69-
{
70-
var message = Marshal.PtrToStringAnsi(errorPtr) ?? "Unknown error";
71-
((delegate* unmanaged[Cdecl]<IntPtr, void>)loader.GetFunctionPointer("free_error"))(errorPtr);
72-
return message;
73-
}
70+
var message = Marshal.PtrToStringAnsi(errorPtr) ?? "Unknown error";
71+
((delegate* unmanaged[Cdecl]<IntPtr, void>)GetFunctionPointer("free_error"))(errorPtr);
72+
throw new CppException(message);
7473
}
7574

7675
protected virtual void Dispose()

0 commit comments

Comments
 (0)