Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,91 @@ internal static ParameterSyntax GetTrampolineInvokeParameter (string trampolineN
.NormalizeWhitespace ();
}

/// <summary>
///
/// </summary>
/// <param name="typeInfo"></param>
/// <returns></returns>
internal static TypeSyntax GetLowLevelType (in TypeInfo typeInfo)
{
#pragma warning disable format
return typeInfo switch {
// pointer parameter
{ IsPointer: true } => typeInfo.GetIdentifierSyntax (),

// delegate parameter is a NativeHandle
{ IsDelegate: true } => IntPtr,

// native enum, return the conversion expression to the native type
{ IsNativeEnum: true} => IdentifierName(typeInfo.EnumUnderlyingType!.Value.GetKeyword ()),

// boolean, convert it to byte
{ SpecialType: SpecialType.System_Boolean } => PredefinedType (Token(SyntaxKind.ByteKeyword)),

{ IsArray: true } => NativeHandle,

{ SpecialType: SpecialType.System_String } => NativeHandle,

{ IsProtocol: true } => NativeHandle,

// special types

// CoreMedia.CMSampleBuffer
{ FullyQualifiedName: "CoreMedia.CMSampleBuffer" } => NativeHandle,

// AudioToolbox.AudioBuffers
{ FullyQualifiedName: "AudioToolbox.AudioBuffers" } => NativeHandle,

// general NSObject/INativeObject, has to be after the special types otherwise the special types will
// fall into the NSObject/INativeObject case

// same name, native handle
{ IsNSObject: true } => NativeHandle,

// same name, native handle
{ IsINativeObject: true } => NativeHandle,

// by default, we will use the parameter name as is and the type of the parameter
_ => typeInfo.GetIdentifierSyntax (),
};
#pragma warning restore format
}

/// <summary>
/// Returns the needed data to build the parameter syntax for the native trampoline delegate.
/// </summary>
/// <param name="parameter">The parameter we want to generate for the lower invoke method.</param>
/// <returns>The parameter syntax needed for the parameter.</returns>
internal static ParameterSyntax GetTrampolineInvokeParameter (in DelegateParameter parameter)
{
// in the general case we will return the low level type conversion of the parameter type but we
// need to handle in a special case those parameters that are passed by reference
var parameterIdentifier = Identifier (parameter.Name);
#pragma warning disable format
(SyntaxToken ParameterName, TypeSyntax ParameterType) parameterInfo = parameter switch {
// parameters that are passed by reference, depend on the type that is referenced
{ IsByRef: true, Type.IsReferenceType: false, Type.IsNullable: true}
=> (parameterIdentifier,
PointerType (IdentifierName (parameter.Type.FullyQualifiedName))),

{ IsByRef: true, Type.SpecialType: SpecialType.System_Boolean}
=> (parameterIdentifier,
PointerType (PredefinedType (Token(SyntaxKind.ByteKeyword)))),

{ IsByRef: true, Type.IsReferenceType: true, Type.IsNullable: false}
=> (parameterIdentifier,
PointerType (NativeHandle)),

// by default, we will use the parameter name as is and the type of the parameter
_ => (parameterIdentifier, GetLowLevelType (parameter.Type)),
};
#pragma warning restore format

return Parameter (parameterInfo.ParameterName)
.WithType (parameterInfo.ParameterType)
.NormalizeWhitespace ();
}

/// <summary>
/// Returns the argument syntax of a parameter to be used for the trampoliner to invoke a delegate.
/// </summary>
Expand Down Expand Up @@ -533,4 +618,43 @@ internal static StatementSyntax CallTrampolineDelegate (in DelegateInfo delegate
EqualsValueClause (invocation.WithLeadingTrivia (Space)).WithLeadingTrivia (Space))));
return LocalDeclarationStatement (declaration);
}

/// <summary>
/// Return the delegate declaration for the trampoline delegate. The trampoline delegate is a delegate that
/// takes as a first parameter a IntPtr that represents the block to be called. The rest of the parameters are
/// the same as the original delegate.
/// </summary>
/// <param name="delegateTypeInfo">The delegate type information.</param>
/// <param name="delegateName">The name of the delegate generated.</param>
/// <returns>The syntax of the delegate.</returns>
internal static SyntaxNode GetTrampolineDelegateDeclaration (in TypeInfo delegateTypeInfo, out string delegateName)
{
// generate a new delegate type with the addition of the IntPtr parameter for block
var modifiers = TokenList (Token (SyntaxKind.UnsafeKeyword), Token (SyntaxKind.InternalKeyword));
delegateName = Nomenclator.GetTrampolineClassName (delegateTypeInfo.Name, Nomenclator.TrampolineClassType.DelegateType);

// build the arguments for the delegate, but add a IntPtr parameter at the start of the list
var parameterBucket = ImmutableArray.CreateBuilder<ParameterSyntax> (delegateTypeInfo.Delegate!.Parameters.Length + 1);
// block parameter needed for the trampoline
parameterBucket.Add (
Parameter (Identifier (Nomenclator.GetTrampolineBlockParameterName ()))
.WithType (IntPtr));
// calculate the rest of the parameters
foreach (var parameterInfo in delegateTypeInfo.Delegate!.Parameters) {
// build the parameter
parameterBucket.Add (GetTrampolineInvokeParameter (parameterInfo));
}

var parametersSyntax = ParameterList (
SeparatedList<ParameterSyntax> (
parameterBucket.ToImmutableArray ().ToSyntaxNodeOrTokenArray ())).NormalizeWhitespace ();
// delegate declaration
var declaration = DelegateDeclaration (
GetLowLevelType (delegateTypeInfo.Delegate!.ReturnType), // return the low level type, not the manged version
Identifier (delegateName))
.WithModifiers (modifiers).NormalizeWhitespace ()
.WithParameterList (parametersSyntax.WithLeadingTrivia (Space));

return declaration;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.Macios.Generator.Extensions;

static class ArgumentSyntaxExtensions {

public static SyntaxNodeOrToken [] ToSyntaxNodeOrTokenArray (this ImmutableArray<ArgumentSyntax> arguments)
public static SyntaxNodeOrToken [] ToSyntaxNodeOrTokenArray<T> (this ImmutableArray<T> arguments) where T : CSharpSyntaxNode
{
// the size of the array is simple to calculate, we need space for all parameters
// and for a comma for each parameter except for the last one
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.Macios.Generator.DataModel;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using ParameterDataModel = Microsoft.Macios.Generator.DataModel.Parameter;
using TypeInfo = Microsoft.Macios.Generator.DataModel.TypeInfo;

namespace Microsoft.Macios.Generator.Formatters;

Expand Down Expand Up @@ -35,24 +36,6 @@ public static ParameterListSyntax GetParameterList (this in ImmutableArray<Param

return ParameterList (SeparatedList<ParameterSyntax> (nodes)).NormalizeWhitespace ();
}
static TypeSyntax GetIdentifierSyntax (this in ParameterDataModel parameter)
{
if (parameter.Type.IsArray) {
// could be a params array or simply an array
var arrayType = ArrayType (IdentifierName (parameter.Type.FullyQualifiedName))
.WithRankSpecifiers (SingletonList (
ArrayRankSpecifier (
SingletonSeparatedList<ExpressionSyntax> (OmittedArraySizeExpression ()))));
return parameter.Type.IsNullable
? NullableType (arrayType)
: arrayType;
}

// dealing with a non-array type
return parameter.Type.IsNullable
? NullableType (IdentifierName (parameter.Type.FullyQualifiedName))
: IdentifierName (parameter.Type.FullyQualifiedName);
}

public static ParameterSyntax ToDeclaration (this in ParameterDataModel parameter)
{
Expand Down Expand Up @@ -89,7 +72,7 @@ public static ParameterSyntax ToDeclaration (this in ParameterDataModel paramete
// }
var syntax = Parameter (Identifier (parameter.Name))
.WithModifiers (modifiers)
.WithType (parameter.GetIdentifierSyntax ());
.WithType (parameter.Type.GetIdentifierSyntax ());

return syntax.NormalizeWhitespace ();
}
Expand Down
7 changes: 7 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/Nomenclator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,11 @@ public static string GetTrampolineClassName (string trampolineName, TrampolineCl
/// </summary>
/// <returns>The name of the variable used to store delegates in trampolines.</returns>
public static string GetTrampolineDelegateVariableName () => "del";

/// <summary>
/// Return the name of the trampoline block parameter. This is the name of the parameter that will be containing the
/// IntPtr to the trampoline block.
/// </summary>
/// <returns>The name to be used in the delegate.</returns>
public static string GetTrampolineBlockParameterName () => "block";
}
Loading
Loading