Skip to content
This repository has been archived by the owner on Jul 26, 2023. It is now read-only.

Commit

Permalink
Merge pull request #131 from AArnott/fix130_codegen
Browse files Browse the repository at this point in the history
Add code generator for IntPtr property accessors
  • Loading branch information
AArnott committed Dec 30, 2015
2 parents 193a394 + 4bb7b04 commit 6977f7d
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/CodeGeneration/CodeGeneration.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="OfferIntPtrOverloadGenerator.cs" />
<Compile Include="OfferIntPtrPropertyAccessorsGenerator.cs" />
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
Expand Down
6 changes: 2 additions & 4 deletions src/CodeGeneration/OfferIntPtrOverloadGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ public OfferIntPtrOverloadGenerator(AttributeData data)
}

/// <inheritdoc />
public Task<IReadOnlyList<MemberDeclarationSyntax>> GenerateAsync(MemberDeclarationSyntax applyTo, Document document, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
public Task<SyntaxList<MemberDeclarationSyntax>> GenerateAsync(MemberDeclarationSyntax applyTo, Document document, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
{
var type = (ClassDeclarationSyntax)applyTo;
var result = new List<MemberDeclarationSyntax>();
var generatedType = type
.WithMembers(SyntaxFactory.List<MemberDeclarationSyntax>());
var methodsWithNativePointers =
Expand All @@ -56,8 +55,7 @@ where WhereIsPointerParameter(method.ParameterList.Parameters).Any()
generatedType = generatedType.AddMembers(intPtrOverload);
}

result.Add(generatedType);
return Task.FromResult<IReadOnlyList<MemberDeclarationSyntax>>(result);
return Task.FromResult(SyntaxFactory.SingletonList<MemberDeclarationSyntax>(generatedType));
}

private static IEnumerable<ParameterSyntax> WhereIsPointerParameter(IEnumerable<ParameterSyntax> parameters)
Expand Down
107 changes: 107 additions & 0 deletions src/CodeGeneration/OfferIntPtrPropertyAccessorsGenerator.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Generates property accessors that expose native pointer fields
/// as <see cref="IntPtr"/> properties.
/// </summary>
public class OfferIntPtrPropertyAccessorsGenerator : ICodeGenerator
{
private static readonly TypeSyntax VoidStar = SyntaxFactory.ParseTypeName("void*");

private static readonly TypeSyntax IntPtrTypeSyntax = SyntaxFactory.ParseTypeName("System.IntPtr");

/// <summary>
/// Initializes a new instance of the <see cref="OfferIntPtrPropertyAccessorsGenerator"/> class.
/// </summary>
/// <param name="data">Generator attribute data.</param>
public OfferIntPtrPropertyAccessorsGenerator(AttributeData data)
{
}

/// <inheritdoc />
public Task<SyntaxList<MemberDeclarationSyntax>> GenerateAsync(MemberDeclarationSyntax applyTo, Document document, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
{
var applyToStruct = applyTo as StructDeclarationSyntax;
var applyToClass = applyTo as ClassDeclarationSyntax;
var applyToType = applyTo as TypeDeclarationSyntax;

var generatedMembers = SyntaxFactory.List<MemberDeclarationSyntax>();
var nativePointerFields = from field in applyToType.Members.OfType<FieldDeclarationSyntax>()
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<AttributeListSyntax>())
?? applyToClass?.WithMembers(generatedMembers)
.WithAttributeLists(SyntaxFactory.List<AttributeListSyntax>());
return Task.FromResult(SyntaxFactory.SingletonList<MemberDeclarationSyntax>(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);
}
}
}
2 changes: 1 addition & 1 deletion src/CodeGeneration/project.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"dependencies": {
"CodeGeneration.Roslyn": {
"version": "0.1.43-alpha",
"version": "0.1.48-alpha-gaa3f482974",
"suppressParent": "none"
},
"Nerdbank.GitVersioning": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
<Compile Include="..\CodeGenerationAttributes\OfferIntPtrOverloadsAttribute.cs">
<Link>OfferIntPtrOverloadsAttribute.cs</Link>
</Compile>
<Compile Include="..\CodeGenerationAttributes\OfferIntPtrPropertyAccessorsAttribute.cs">
<Link>OfferIntPtrPropertyAccessorsAttribute.cs</Link>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))\EnlistmentInfo.targets" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))' != '' " />
Expand Down
2 changes: 1 addition & 1 deletion src/CodeGenerationAttributes.Net40/project.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"dependencies": {
"CodeGeneration.Roslyn": {
"version": "0.1.43-alpha",
"version": "0.1.48-alpha-gaa3f482974",
"suppressParent": "none"
},
"Nerdbank.GitVersioning": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="OfferIntPtrOverloadsAttribute.cs" />
<Compile Include="OfferIntPtrPropertyAccessorsAttribute.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Causes generation of property accessors that expose native pointer fields
/// as <see cref="IntPtr"/> properties.
/// </summary>
[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
{
}
}
2 changes: 1 addition & 1 deletion src/CodeGenerationAttributes/project.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"dependencies": {
"CodeGeneration.Roslyn": {
"version": "0.1.43-alpha",
"version": "0.1.48-alpha-gaa3f482974",
"suppressParent": "none"
},
"Nerdbank.GitVersioning": {
Expand Down
1 change: 1 addition & 0 deletions src/nuget.config
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="myget.org/F/aarnott" value="https://www.myget.org/F/aarnott/api/v3/index.json" />
<add key="CodeGeneration.Roslyn CI" value="https://ci.appveyor.com/nuget/codegeneration-roslyn" />
</packageSources>
</configuration>

0 comments on commit 6977f7d

Please sign in to comment.