From 4bb7b047c74a91b980cab30cd8f567691a4dc43c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 29 Dec 2015 20:35:47 -0800 Subject: [PATCH] Add code generator for IntPtr property accessors Provides the infrastructural support for #130 --- src/CodeGeneration/CodeGeneration.csproj | 1 + .../OfferIntPtrOverloadGenerator.cs | 6 +- .../OfferIntPtrPropertyAccessorsGenerator.cs | 107 ++++++++++++++++++ src/CodeGeneration/project.json | 2 +- .../CodeGenerationAttributes.Net40.csproj | 3 + .../project.json | 2 +- .../CodeGenerationAttributes.csproj | 1 + .../OfferIntPtrPropertyAccessorsAttribute.cs | 20 ++++ src/CodeGenerationAttributes/project.json | 2 +- src/nuget.config | 1 + 10 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 src/CodeGeneration/OfferIntPtrPropertyAccessorsGenerator.cs create mode 100644 src/CodeGenerationAttributes/OfferIntPtrPropertyAccessorsAttribute.cs diff --git a/src/CodeGeneration/CodeGeneration.csproj b/src/CodeGeneration/CodeGeneration.csproj index a3ed24f5..5c79b90e 100644 --- a/src/CodeGeneration/CodeGeneration.csproj +++ b/src/CodeGeneration/CodeGeneration.csproj @@ -31,6 +31,7 @@ + diff --git a/src/CodeGeneration/OfferIntPtrOverloadGenerator.cs b/src/CodeGeneration/OfferIntPtrOverloadGenerator.cs index 6c8fee6b..eaffff2d 100644 --- a/src/CodeGeneration/OfferIntPtrOverloadGenerator.cs +++ b/src/CodeGeneration/OfferIntPtrOverloadGenerator.cs @@ -32,10 +32,9 @@ public OfferIntPtrOverloadGenerator(AttributeData data) } /// - public Task> GenerateAsync(MemberDeclarationSyntax applyTo, Document document, IProgress progress, CancellationToken cancellationToken) + public Task> GenerateAsync(MemberDeclarationSyntax applyTo, Document document, IProgress progress, CancellationToken cancellationToken) { var type = (ClassDeclarationSyntax)applyTo; - var result = new List(); var generatedType = type .WithMembers(SyntaxFactory.List()); var methodsWithNativePointers = @@ -56,8 +55,7 @@ where WhereIsPointerParameter(method.ParameterList.Parameters).Any() generatedType = generatedType.AddMembers(intPtrOverload); } - result.Add(generatedType); - return Task.FromResult>(result); + return Task.FromResult(SyntaxFactory.SingletonList(generatedType)); } private static IEnumerable WhereIsPointerParameter(IEnumerable parameters) diff --git a/src/CodeGeneration/OfferIntPtrPropertyAccessorsGenerator.cs b/src/CodeGeneration/OfferIntPtrPropertyAccessorsGenerator.cs new file mode 100644 index 00000000..62670d10 --- /dev/null +++ b/src/CodeGeneration/OfferIntPtrPropertyAccessorsGenerator.cs @@ -0,0 +1,107 @@ +// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + +namespace PInvoke +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + using CodeGeneration.Roslyn; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; + + /// + /// Generates property accessors that expose native pointer fields + /// as properties. + /// + public class OfferIntPtrPropertyAccessorsGenerator : ICodeGenerator + { + private static readonly TypeSyntax VoidStar = SyntaxFactory.ParseTypeName("void*"); + + private static readonly TypeSyntax IntPtrTypeSyntax = SyntaxFactory.ParseTypeName("System.IntPtr"); + + /// + /// Initializes a new instance of the class. + /// + /// Generator attribute data. + public OfferIntPtrPropertyAccessorsGenerator(AttributeData data) + { + } + + /// + public Task> GenerateAsync(MemberDeclarationSyntax applyTo, Document document, IProgress progress, CancellationToken cancellationToken) + { + var applyToStruct = applyTo as StructDeclarationSyntax; + var applyToClass = applyTo as ClassDeclarationSyntax; + var applyToType = applyTo as TypeDeclarationSyntax; + + var generatedMembers = SyntaxFactory.List(); + var nativePointerFields = from field in applyToType.Members.OfType() + where field.Declaration.Type is PointerTypeSyntax && field.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)) + select field; + foreach (var field in nativePointerFields) + { + foreach (var variable in field.Declaration.Variables) + { + generatedMembers = generatedMembers.Add( + SyntaxFactory.PropertyDeclaration(IntPtrTypeSyntax, variable.Identifier.ValueText + "_IntPtr") + .WithModifiers(field.Modifiers) + //// get { return new IntPtr(this.field); } + //// set { this.field = (byte*)value.ToPointer(); } + .AddAccessorListAccessors( + SyntaxFactory.AccessorDeclaration( + SyntaxKind.GetAccessorDeclaration, + SyntaxFactory.Block( + SyntaxFactory.ReturnStatement( + SyntaxFactory.ObjectCreationExpression(IntPtrTypeSyntax) + .AddArgumentListArguments(SyntaxFactory.Argument(ThisDot(variable.Identifier)))))), + SyntaxFactory.AccessorDeclaration( + SyntaxKind.SetAccessorDeclaration, + SyntaxFactory.Block( + SyntaxFactory.ExpressionStatement( + SyntaxFactory.AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + ThisDot(variable.Identifier), + TypedAs( + SyntaxFactory.InvocationExpression( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName("value"), + SyntaxFactory.IdentifierName(nameof(IntPtr.ToPointer))), + SyntaxFactory.ArgumentList()), + field.Declaration.Type))))))); + } + } + + var generatedType = (TypeDeclarationSyntax)applyToStruct?.WithMembers(generatedMembers) + .WithAttributeLists(SyntaxFactory.List()) + ?? applyToClass?.WithMembers(generatedMembers) + .WithAttributeLists(SyntaxFactory.List()); + return Task.FromResult(SyntaxFactory.SingletonList(generatedType)); + } + + private static MemberAccessExpressionSyntax ThisDot(SyntaxToken memberName) + { + return ThisDot(SyntaxFactory.IdentifierName(memberName.ValueText)); + } + + private static MemberAccessExpressionSyntax ThisDot(SimpleNameSyntax memberName) + { + return SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.ThisExpression(), + memberName); + } + + private static ExpressionSyntax TypedAs(ExpressionSyntax expression, TypeSyntax requiredType) + { + return VoidStar.Equals(requiredType) + ? expression + : SyntaxFactory.CastExpression(requiredType, expression); + } + } +} diff --git a/src/CodeGeneration/project.json b/src/CodeGeneration/project.json index e3ac3137..b690ce63 100644 --- a/src/CodeGeneration/project.json +++ b/src/CodeGeneration/project.json @@ -1,7 +1,7 @@ { "dependencies": { "CodeGeneration.Roslyn": { - "version": "0.1.43-alpha", + "version": "0.1.48-alpha-gaa3f482974", "suppressParent": "none" }, "Nerdbank.GitVersioning": { diff --git a/src/CodeGenerationAttributes.Net40/CodeGenerationAttributes.Net40.csproj b/src/CodeGenerationAttributes.Net40/CodeGenerationAttributes.Net40.csproj index b6a0f1ae..0bf74493 100644 --- a/src/CodeGenerationAttributes.Net40/CodeGenerationAttributes.Net40.csproj +++ b/src/CodeGenerationAttributes.Net40/CodeGenerationAttributes.Net40.csproj @@ -34,6 +34,9 @@ OfferIntPtrOverloadsAttribute.cs + + OfferIntPtrPropertyAccessorsAttribute.cs + diff --git a/src/CodeGenerationAttributes.Net40/project.json b/src/CodeGenerationAttributes.Net40/project.json index f5a3e873..5443e50d 100644 --- a/src/CodeGenerationAttributes.Net40/project.json +++ b/src/CodeGenerationAttributes.Net40/project.json @@ -1,7 +1,7 @@ { "dependencies": { "CodeGeneration.Roslyn": { - "version": "0.1.43-alpha", + "version": "0.1.48-alpha-gaa3f482974", "suppressParent": "none" }, "Nerdbank.GitVersioning": { diff --git a/src/CodeGenerationAttributes/CodeGenerationAttributes.csproj b/src/CodeGenerationAttributes/CodeGenerationAttributes.csproj index 216f9cea..cc5bda80 100644 --- a/src/CodeGenerationAttributes/CodeGenerationAttributes.csproj +++ b/src/CodeGenerationAttributes/CodeGenerationAttributes.csproj @@ -29,6 +29,7 @@ + diff --git a/src/CodeGenerationAttributes/OfferIntPtrPropertyAccessorsAttribute.cs b/src/CodeGenerationAttributes/OfferIntPtrPropertyAccessorsAttribute.cs new file mode 100644 index 00000000..f689fd6b --- /dev/null +++ b/src/CodeGenerationAttributes/OfferIntPtrPropertyAccessorsAttribute.cs @@ -0,0 +1,20 @@ +// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + +namespace PInvoke +{ + using System; + using System.Diagnostics; + using CodeGeneration.Roslyn; + + /// + /// Causes generation of property accessors that expose native pointer fields + /// as properties. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] + [CodeGenerationAttribute("PInvoke.OfferIntPtrPropertyAccessorsGenerator, CodeGeneration, Version=0.1.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a")] + [Conditional("CodeGeneration")] + public class OfferIntPtrPropertyAccessorsAttribute : Attribute + { + } +} diff --git a/src/CodeGenerationAttributes/project.json b/src/CodeGenerationAttributes/project.json index 26d98a83..6ca8bcba 100644 --- a/src/CodeGenerationAttributes/project.json +++ b/src/CodeGenerationAttributes/project.json @@ -1,7 +1,7 @@ { "dependencies": { "CodeGeneration.Roslyn": { - "version": "0.1.43-alpha", + "version": "0.1.48-alpha-gaa3f482974", "suppressParent": "none" }, "Nerdbank.GitVersioning": { diff --git a/src/nuget.config b/src/nuget.config index 415563dd..dbdceb2b 100644 --- a/src/nuget.config +++ b/src/nuget.config @@ -6,5 +6,6 @@ +