private ExpressionSyntax CastToManagedIfNecessary(ExpressionSyntax expression) { // Skip the cast if the managed and unmanaged element types are the same if (_unmanagedElementType.IsEquivalentTo(_managedElementType)) { return(expression); } // MemoryMarshal.Cast<<unmanagedElementType>, <elementType>>(<expression>) return(InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), GenericName( Identifier("Cast"), TypeArgumentList(SeparatedList( new[] { _unmanagedElementType, _managedElementType })))), ArgumentList(SingletonSeparatedList( Argument(expression))))); }
private IEnumerable <StatementSyntax> GeneratePinningPath(TypePositionInfo info, StubCodeContext context) { (string managedIdentifer, string nativeIdentifier) = context.GetIdentifiers(info); string byRefIdentifier = $"__byref_{managedIdentifer}"; // The element type here is used only for refs/pointers. In the pointer array case, we use byte as the basic placeholder type, // since we can't use pointer types in generic type parameters. bool isPointerArray = info.ManagedType is SzArrayType arrayType && arrayType.ElementTypeInfo is PointerTypeInfo; TypeSyntax arrayElementType = isPointerArray ? PredefinedType(Token(SyntaxKind.ByteKeyword)) : _elementType; if (context.CurrentStage == StubCodeContext.Stage.Marshal) { // [COMPAT] We use explicit byref calculations here instead of just using a fixed statement // since a fixed statement converts a zero-length array to a null pointer. // Many native APIs, such as GDI+, ICU, etc. validate that an array parameter is non-null // even when the passed in array length is zero. To avoid breaking customers that want to move // to source-generated interop in subtle ways, we explicitly pass a reference to the 0-th element // of an array as long as it is non-null, matching the behavior of the built-in interop system // for single-dimensional zero-based arrays. // ref <elementType> <byRefIdentifier> = ref <managedIdentifer> == null ? ref *(<elementType>*)0 : ref MemoryMarshal.GetArrayDataReference(<managedIdentifer>); PrefixUnaryExpressionSyntax nullRef = PrefixUnaryExpression(SyntaxKind.PointerIndirectionExpression, CastExpression( PointerType(arrayElementType), LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0)))); InvocationExpressionSyntax getArrayDataReference = InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), IdentifierName("GetArrayDataReference")), ArgumentList(SingletonSeparatedList( Argument(IdentifierName(managedIdentifer))))); yield return(LocalDeclarationStatement( VariableDeclaration( RefType(arrayElementType)) .WithVariables(SingletonSeparatedList( VariableDeclarator(Identifier(byRefIdentifier)) .WithInitializer(EqualsValueClause( RefExpression(ParenthesizedExpression( ConditionalExpression( BinaryExpression( SyntaxKind.EqualsExpression, IdentifierName(managedIdentifer), LiteralExpression( SyntaxKind.NullLiteralExpression)), RefExpression(nullRef), RefExpression(getArrayDataReference)))))))))); } if (context.CurrentStage == StubCodeContext.Stage.Pin) { TypeSyntax nativeType = AsNativeType(info); // We skip the Unsafe.As if the element type and native element type are equivalent (ignoring trivia differences) // &<byrefIdentifier> // or // &Unsafe.As<elementType, nativeElementType>(ref <byrefIdentifier>) TypeSyntax nativeElementType = nativeType is PointerTypeSyntax pointerType ? pointerType.ElementType : nativeType; var initializer = arrayElementType.IsEquivalentTo(nativeElementType, topLevel: true) ? PrefixUnaryExpression(SyntaxKind.AddressOfExpression, IdentifierName(byRefIdentifier)) : PrefixUnaryExpression(SyntaxKind.AddressOfExpression, InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ParseTypeName(TypeNames.System_Runtime_CompilerServices_Unsafe), GenericName("As").AddTypeArgumentListArguments( arrayElementType, nativeElementType))) .AddArgumentListArguments( Argument(IdentifierName(byRefIdentifier)) .WithRefKindKeyword(Token(SyntaxKind.RefKeyword)))); // fixed (<nativeType> <nativeIdentifier> = <initializer>) yield return(FixedStatement( VariableDeclaration(nativeType, SingletonSeparatedList( VariableDeclarator(nativeIdentifier) .WithInitializer(EqualsValueClause(initializer)))), EmptyStatement())); } }
// internal static readonly AstNode wherePatternCase1 = // new InvocationExpression( // new MemberReferenceExpression( // new InvocationExpression( // new MemberReferenceExpression(new AnyNode("target"), "Where"), // new LambdaExpression { // Parameters = { PatternHelper.NamedParameter ("param1", PatternHelper.AnyType ("paramType", true), Pattern.AnyString) }, // Body = PatternHelper.OptionalParentheses (new IsExpression(new AnyNode("expr1"), new AnyNode("type"))) // } // ), "Select"), // new LambdaExpression { // Parameters = { PatternHelper.NamedParameter ("param2", PatternHelper.AnyType ("paramType", true), Pattern.AnyString) }, // Body = PatternHelper.OptionalParentheses (new AsExpression(PatternHelper.OptionalParentheses (new AnyNode("expr2")), new Backreference("type"))) // } // ); // // internal static readonly AstNode wherePatternCase2 = // new InvocationExpression( // new MemberReferenceExpression( // new InvocationExpression( // new MemberReferenceExpression(new AnyNode("target"), "Where"), // new LambdaExpression { // Parameters = { PatternHelper.NamedParameter ("param1", PatternHelper.AnyType ("paramType", true), Pattern.AnyString) }, // Body = PatternHelper.OptionalParentheses (new IsExpression(PatternHelper.OptionalParentheses (new AnyNode("expr1")), new AnyNode("type"))) // } // ), "Select"), // new LambdaExpression { // Parameters = { PatternHelper.NamedParameter ("param2", PatternHelper.AnyType ("paramType", true), Pattern.AnyString) }, // Body = PatternHelper.OptionalParentheses (new CastExpression(new Backreference("type"), PatternHelper.OptionalParentheses (new AnyNode("expr2")))) // } // ); static bool MatchWhereSelect(InvocationExpressionSyntax selectInvoke, out ExpressionSyntax target, out TypeSyntax type) { target = null; type = null; if (selectInvoke.ArgumentList.Arguments.Count != 1) { return(false); } var anyInvokeBase = selectInvoke.Expression as MemberAccessExpressionSyntax; if (anyInvokeBase == null || anyInvokeBase.Name.Identifier.Text != "Select") { return(false); } var whereInvoke = anyInvokeBase.Expression as InvocationExpressionSyntax; if (whereInvoke == null || whereInvoke.ArgumentList.Arguments.Count != 1) { return(false); } var baseMember = whereInvoke.Expression as MemberAccessExpressionSyntax; if (baseMember == null || baseMember.Name.Identifier.Text != "Where") { return(false); } target = baseMember.Expression; ParameterSyntax param1, param2; ExpressionSyntax expr1, expr2; if (!ExtractLambda(whereInvoke.ArgumentList.Arguments[0], out param1, out expr1)) { return(false); } if (!ExtractLambda(selectInvoke.ArgumentList.Arguments[0], out param2, out expr2)) { return(false); } if (!expr1.IsKind(SyntaxKind.IsExpression)) { return(false); } type = (expr1 as BinaryExpressionSyntax)?.Right as TypeSyntax; if (type == null) { return(false); } if (expr2.IsKind(SyntaxKind.AsExpression)) { if (!CompareNames(param2, (expr2 as BinaryExpressionSyntax).Left as IdentifierNameSyntax)) { return(false); } if (!type.IsEquivalentTo((expr2 as BinaryExpressionSyntax)?.Right)) { return(false); } } else if (expr2.IsKind(SyntaxKind.CastExpression)) { if (!CompareNames(param2, (expr2 as CastExpressionSyntax)?.Expression.SkipParens() as IdentifierNameSyntax)) { return(false); } if (!type.IsEquivalentTo((expr2 as CastExpressionSyntax)?.Type)) { return(false); } } else { return(false); } if (!CompareNames(param1, (expr1 as BinaryExpressionSyntax)?.Left as IdentifierNameSyntax)) { return(false); } return(target != null); }
public IEnumerable <StatementSyntax> GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable <ArgumentSyntax> nativeTypeConstructorArguments) { if (!_shape.HasFlag(MarshallerShape.ToUnmanaged)) { yield break; } (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); string numElementsIdentifier = GetNumElementsIdentifier(info, context); // <nativeIdentifier> = <marshallerType>.AllocateContainerForUnmanagedElements(<managedIdentifier>, out <numElements>); yield return(ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName(nativeIdentifier), InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, _marshallerTypeSyntax, IdentifierName(ShapeMemberNames.LinearCollection.Stateless.AllocateContainerForUnmanagedElements)), ArgumentList(SeparatedList(new ArgumentSyntax[] { Argument(IdentifierName(managedIdentifier)), Argument(IdentifierName(numElementsIdentifier)) .WithRefOrOutKeyword(Token(SyntaxKind.OutKeyword)) })))))); // <marshallerType>.GetUnmanagedValuesDestination(<nativeIdentifier>, <numElements>) ExpressionSyntax destination = InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, _marshallerTypeSyntax, IdentifierName(ShapeMemberNames.LinearCollection.Stateless.GetUnmanagedValuesDestination)), ArgumentList(SeparatedList(new ArgumentSyntax[] { Argument(IdentifierName(nativeIdentifier)), Argument(IdentifierName(numElementsIdentifier)), }))); if (!info.IsByRef && info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.Out) { // If the parameter is marshalled by-value [Out], then we don't marshal the contents of the collection. // We do clear the span, so that if the invoke target doesn't fill it, we aren't left with undefined content. // <marshallerType>.GetUnmanagedValuesDestination(<nativeIdentifier>, <numElements>).Clear(); yield return(ExpressionStatement( InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, destination, IdentifierName("Clear"))))); yield break; } // Skip the cast if the managed and unmanaged element types are the same if (!_unmanagedElementType.IsEquivalentTo(_managedElementType)) { // MemoryMarshal.Cast<<unmanagedElementType>, <managedElementType>>(<destination>) destination = InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), GenericName( Identifier("Cast")) .WithTypeArgumentList( TypeArgumentList( SeparatedList( new[] { _unmanagedElementType, _managedElementType })))), ArgumentList(SingletonSeparatedList( Argument(destination)))); } // <marshallerType>.GetManagedValuesSource(<managedIdentifer>).CopyTo(<destination>); yield return(ExpressionStatement( InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, _marshallerTypeSyntax, IdentifierName(ShapeMemberNames.LinearCollection.Stateless.GetManagedValuesSource)), ArgumentList(SingletonSeparatedList( Argument(IdentifierName(managedIdentifier))))), IdentifierName("CopyTo"))) .AddArgumentListArguments( Argument(destination)))); }
public static bool IsVoid(this TypeSyntax type) { return(type.IsEquivalentTo(PredefinedType(VoidKeyword.ToToken()), false)); }