private static BlockSyntax CallNativePointerOverload(MethodDeclarationSyntax nativePointerOverload, GeneratorFlags flags, IReadOnlyDictionary <ParameterSyntax, FriendlyFlags> parametersToFriendlyTransform) { Func <ParameterSyntax, IdentifierNameSyntax> getLocalSubstituteName = p => SyntaxFactory.IdentifierName(p.Identifier.ValueText + "Local"); var invocationArguments = new Dictionary <ParameterSyntax, ArgumentSyntax>(); foreach (var p in nativePointerOverload.ParameterList.Parameters) { var refOrOut = p.Modifiers.FirstOrDefault(m => m.IsKind(SyntaxKind.RefKeyword) || m.IsKind(SyntaxKind.OutKeyword)); invocationArguments[p] = SyntaxFactory .Argument(SyntaxFactory.IdentifierName(p.Identifier)) .WithRefOrOutKeyword(refOrOut); } var prelude = new List <StatementSyntax>(); var postlude = new List <StatementSyntax>(); var fixedStatements = new List <FixedStatementSyntax>(); foreach (var parameter in nativePointerOverload.ParameterList.Parameters.Where(p => p.Type is PointerTypeSyntax)) { var parameterName = SyntaxFactory.IdentifierName(parameter.Identifier); var localVarName = getLocalSubstituteName(parameter); FriendlyFlags friendlyFlags; if (flags.HasFlag(GeneratorFlags.NativePointerToFriendly) && parametersToFriendlyTransform.TryGetValue(parameter, out friendlyFlags)) { if (friendlyFlags.HasFlag(FriendlyFlags.Array)) { var fixedArrayDecl = SyntaxFactory.VariableDeclarator(localVarName.Identifier) .WithInitializer(SyntaxFactory.EqualsValueClause(parameterName)); fixedStatements.Add(SyntaxFactory.FixedStatement( SyntaxFactory.VariableDeclaration(parameter.Type).AddVariables(fixedArrayDecl), SyntaxFactory.Block())); invocationArguments[parameter] = invocationArguments[parameter].WithExpression(localVarName); } else { if (friendlyFlags.HasFlag(FriendlyFlags.Optional)) { var nullableType = (PointerTypeSyntax)parameter.Type; var hasValueExpression = SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(parameter.Identifier), SyntaxFactory.IdentifierName(nameof(Nullable <int> .HasValue))); var valueExpression = SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(parameter.Identifier), SyntaxFactory.IdentifierName(nameof(Nullable <int> .Value))); var defaultExpression = SyntaxFactory.DefaultExpression(nullableType.ElementType); var varStatement = SyntaxFactory.VariableDeclaration(nullableType.ElementType).AddVariables( SyntaxFactory.VariableDeclarator(localVarName.Identifier) .WithInitializer(SyntaxFactory.EqualsValueClause( SyntaxFactory.ConditionalExpression( hasValueExpression, valueExpression, defaultExpression)))); prelude.Add(SyntaxFactory.LocalDeclarationStatement(varStatement)); if (friendlyFlags.HasFlag(FriendlyFlags.Out)) { // someParam = someParamLocal; var assignBackToParameter = SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, parameterName, localVarName); var conditionalStatement = SyntaxFactory.IfStatement( hasValueExpression, SyntaxFactory.ExpressionStatement(assignBackToParameter)); postlude.Add(conditionalStatement); } invocationArguments[parameter] = invocationArguments[parameter].WithExpression( SyntaxFactory.ConditionalExpression( hasValueExpression, SyntaxFactory.PrefixUnaryExpression(SyntaxKind.AddressOfExpression, localVarName), SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression))); } else if (friendlyFlags.HasFlag(FriendlyFlags.Out)) { var fixedDecl = SyntaxFactory.VariableDeclarator(localVarName.Identifier) .WithInitializer(SyntaxFactory.EqualsValueClause( SyntaxFactory.PrefixUnaryExpression( SyntaxKind.AddressOfExpression, parameterName))); fixedStatements.Add(SyntaxFactory.FixedStatement( SyntaxFactory.VariableDeclaration(parameter.Type).AddVariables(fixedDecl), SyntaxFactory.Block())); invocationArguments[parameter] = invocationArguments[parameter].WithExpression(localVarName); } else { invocationArguments[parameter] = invocationArguments[parameter] .WithExpression(SyntaxFactory.PrefixUnaryExpression(SyntaxKind.AddressOfExpression, parameterName)); } } } else if (flags.HasFlag(GeneratorFlags.NativePointerToIntPtr)) { var varStatement = SyntaxFactory.VariableDeclaration(parameter.Type); var declarator = SyntaxFactory.VariableDeclarator(localVarName.Identifier); if (parameter.Modifiers.Any(m => m.IsKind(SyntaxKind.OutKeyword))) { var assignment = SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, parameterName, SyntaxFactory.ObjectCreationExpression( IntPtrTypeSyntax, SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(localVarName))), null)); postlude.Add(SyntaxFactory.ExpressionStatement(assignment)); } else { var voidStarPointer = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(parameter.Identifier), SyntaxFactory.IdentifierName(nameof(IntPtr.ToPointer))), SyntaxFactory.ArgumentList()); var typedPointer = parameter.Type.Equals(VoidStar) ? (ExpressionSyntax)voidStarPointer : SyntaxFactory.CastExpression(parameter.Type, voidStarPointer); declarator = declarator.WithInitializer(SyntaxFactory.EqualsValueClause(typedPointer)); } varStatement = varStatement.AddVariables(declarator); prelude.Add(SyntaxFactory.LocalDeclarationStatement(varStatement)); invocationArguments[parameter] = invocationArguments[parameter].WithExpression(localVarName); } } var invocationExpression = SyntaxFactory.InvocationExpression( SyntaxFactory.IdentifierName(nativePointerOverload.Identifier.ValueText), SyntaxFactory.ArgumentList( SyntaxFactory.SeparatedList( from p in nativePointerOverload.ParameterList.Parameters select invocationArguments[p]))); IdentifierNameSyntax resultVariableName = null; StatementSyntax invocationStatement; if (nativePointerOverload.ReturnType != null && (nativePointerOverload.ReturnType as PredefinedTypeSyntax)?.Keyword.Kind() != SyntaxKind.VoidKeyword) { resultVariableName = SyntaxFactory.IdentifierName("result"); // TODO: ensure this is unique. invocationStatement = SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration(nativePointerOverload.ReturnType) .AddVariables( SyntaxFactory.VariableDeclarator(resultVariableName.Identifier) .WithInitializer(SyntaxFactory.EqualsValueClause(invocationExpression)))); } else { invocationStatement = SyntaxFactory.ExpressionStatement(invocationExpression); } var block = SyntaxFactory.Block() .AddStatements(prelude.ToArray()) .AddStatements(invocationStatement) .AddStatements(postlude.ToArray()); if (resultVariableName != null) { ExpressionSyntax returnedValue = nativePointerOverload.ReturnType is PointerTypeSyntax ? (ExpressionSyntax)SyntaxFactory.ObjectCreationExpression( IntPtrTypeSyntax, SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(resultVariableName))), null) : resultVariableName; block = block.AddStatements(SyntaxFactory.ReturnStatement(returnedValue)); } if (fixedStatements.Count > 0) { StatementSyntax outermost = block; foreach (var statement in fixedStatements) { outermost = statement.WithStatement(outermost); } block = SyntaxFactory.Block(outermost); } return(block); }
private static ParameterListSyntax TransformParameterList(ParameterListSyntax list, GeneratorFlags generatorFlags, IReadOnlyDictionary <ParameterSyntax, FriendlyFlags> parametersToFriendlyTransform) { var resultingList = list.ReplaceNodes( WhereIsPointerParameter(list.Parameters), (n1, n2) => { // Remove all attributes n2 = n2.WithAttributeLists(SyntaxFactory.List <AttributeListSyntax>()); FriendlyFlags friendlyFlags; if (generatorFlags.HasFlag(GeneratorFlags.NativePointerToFriendly) && parametersToFriendlyTransform.TryGetValue(n1, out friendlyFlags)) { var pointerType = (PointerTypeSyntax)n2.Type; var alteredParameter = n2.WithDefault(null); if (friendlyFlags.HasFlag(FriendlyFlags.Array)) { alteredParameter = alteredParameter .WithType(SyntaxFactory.ArrayType(pointerType.ElementType, OneDimensionalUnspecifiedLengthArray)); } else { if (friendlyFlags.HasFlag(FriendlyFlags.Optional)) { alteredParameter = alteredParameter .WithType(SyntaxFactory.NullableType(pointerType.ElementType)); } if (friendlyFlags.HasFlag(FriendlyFlags.Out)) { SyntaxKind modifier = friendlyFlags.HasFlag(FriendlyFlags.Optional) || friendlyFlags.HasFlag(FriendlyFlags.In) ? SyntaxKind.RefKeyword : SyntaxKind.OutKeyword; if (!friendlyFlags.HasFlag(FriendlyFlags.Optional)) { alteredParameter = alteredParameter .WithType(pointerType.ElementType); } alteredParameter = alteredParameter .AddModifiers(SyntaxFactory.Token(modifier)); } else if (!friendlyFlags.HasFlag(FriendlyFlags.Optional)) { alteredParameter = alteredParameter .WithType(pointerType.ElementType); } } return(alteredParameter); } else if (generatorFlags.HasFlag(GeneratorFlags.NativePointerToIntPtr)) { return(n2 .WithType(IntPtrTypeSyntax) .WithDefault(null)); } else { return(n2); } }); return(resultingList); }