Skip to content

Commit

Permalink
Implement support for configurable generator options. (dotnet/runtime…
Browse files Browse the repository at this point in the history
  • Loading branch information
jkoritzinsky authored Jan 4, 2021
1 parent d24260a commit 9bc3120
Show file tree
Hide file tree
Showing 13 changed files with 274 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void Execute(GeneratorExecutionContext context)
generatorDiagnostics.ReportTargetFrameworkNotSupported(MinimumSupportedFrameworkVersion);
}

var env = new StubEnvironment(context.Compilation, isSupported, targetFrameworkVersion);
var env = new StubEnvironment(context.Compilation, isSupported, targetFrameworkVersion, context.AnalyzerConfigOptions.GlobalOptions);
var generatedDllImports = new StringBuilder();
foreach (SyntaxReference synRef in synRec.Methods)
{
Expand Down Expand Up @@ -94,7 +94,7 @@ public void Execute(GeneratorExecutionContext context)

// Process the GeneratedDllImport attribute
DllImportStub.GeneratedDllImportData dllImportData;
AttributeSyntax dllImportAttr = this.ProcessGeneratedDllImportAttribute(methodSymbolInfo, generatedDllImportAttr, out dllImportData);
AttributeSyntax dllImportAttr = this.ProcessGeneratedDllImportAttribute(methodSymbolInfo, generatedDllImportAttr, context.AnalyzerConfigOptions.GlobalOptions.GenerateForwarders(), out dllImportData);
Debug.Assert((dllImportAttr is not null) && (dllImportData is not null));

if (dllImportData!.IsUserDefined.HasFlag(DllImportStub.DllImportMember.BestFitMapping))
Expand Down Expand Up @@ -213,6 +213,7 @@ private static bool IsGeneratedDllImportAttribute(AttributeSyntax attrSyntaxMayb
private AttributeSyntax ProcessGeneratedDllImportAttribute(
IMethodSymbol method,
AttributeData attrData,
bool generateForwarders,
out DllImportStub.GeneratedDllImportData dllImportData)
{
dllImportData = new DllImportStub.GeneratedDllImportData();
Expand Down Expand Up @@ -287,7 +288,9 @@ private AttributeSyntax ProcessGeneratedDllImportAttribute(

Debug.Assert(expSyntaxMaybe is not null);

if (PassThroughToDllImportAttribute(namedArg.Key))
// If we're generating a forwarder stub, then all parameters on the GenerateDllImport attribute
// must also be added to the generated DllImport attribute.
if (generateForwarders || PassThroughToDllImportAttribute(namedArg.Key))
{
// Defer the name equals syntax till we know the value means something. If we created
// an expression we know the key value was valid.
Expand Down Expand Up @@ -340,9 +343,6 @@ static ExpressionSyntax CreateEnumExpressionSyntax<T>(T value) where T : Enum

static bool PassThroughToDllImportAttribute(string argName)
{
#if GENERATE_FORWARDER
return true;
#else
// Certain fields on DllImport will prevent inlining. Their functionality should be handled by the
// generated source, so the generated DllImport declaration should not include these fields.
return argName switch
Expand All @@ -355,7 +355,6 @@ static bool PassThroughToDllImportAttribute(string argName)
nameof(DllImportStub.GeneratedDllImportData.SetLastError) => false,
_ => true
};
#endif
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
<LangVersion>Preview</LangVersion>
<Nullable>enable</Nullable>
<RootNamespace>Microsoft.Interop</RootNamespace>

<!-- Uncomment to generate stub code that simply forwards parameters to p/invoke (i.e. no marshalling) -->
<!--<DefineConstants>GENERATE_FORWARDER</DefineConstants>-->
</PropertyGroup>

<PropertyGroup>
Expand Down Expand Up @@ -42,6 +39,7 @@

<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<None Include="Microsoft.Interop.DllImportGenerator.props" Pack="true" PackagePath="build" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace Microsoft.Interop
{
internal record StubEnvironment(
Compilation Compilation,
bool SupportedTargetFramework,
Version TargetFrameworkVersion);
Version TargetFrameworkVersion,
AnalyzerConfigOptions Options);

internal class DllImportStub
{
Expand Down Expand Up @@ -177,7 +179,9 @@ public static DllImportStub Create(
};

var managedRetTypeInfo = retTypeInfo;
if (!dllImportData.PreserveSig)
// Do not manually handle PreserveSig when generating forwarders.
// We want the runtime to handle everything.
if (!dllImportData.PreserveSig && !env.Options.GenerateForwarders())
{
// Create type info for native HRESULT return
retTypeInfo = TypePositionInfo.CreateForType(env.Compilation.GetSpecialType(SpecialType.System_Int32), NoMarshallingInfo.Instance);
Expand All @@ -203,7 +207,7 @@ public static DllImportStub Create(
}

// Generate stub code
var stubGenerator = new StubCodeGenerator(method, dllImportData, paramsTypeInfo, retTypeInfo, diagnostics);
var stubGenerator = new StubCodeGenerator(method, dllImportData, paramsTypeInfo, retTypeInfo, diagnostics, env.Options);
var (code, dllImport) = stubGenerator.GenerateSyntax();

var additionalAttrs = new List<AttributeListSyntax>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace Microsoft.Interop
Expand Down Expand Up @@ -109,7 +110,6 @@ internal class MarshallingGenerators
public static readonly Forwarder Forwarder = new Forwarder();
public static readonly BlittableMarshaller Blittable = new BlittableMarshaller();
public static readonly DelegateMarshaller Delegate = new DelegateMarshaller();
public static readonly SafeHandleMarshaller SafeHandle = new SafeHandleMarshaller();
public static readonly HResultExceptionMarshaller HResultException = new HResultExceptionMarshaller();

/// <summary>
Expand All @@ -120,11 +120,14 @@ internal class MarshallingGenerators
/// <returns>A <see cref="IMarshallingGenerator"/> instance.</returns>
public static IMarshallingGenerator Create(
TypePositionInfo info,
StubCodeContext context)
StubCodeContext context,
AnalyzerConfigOptions options)
{
#if GENERATE_FORWARDER
return MarshallingGenerators.Forwarder;
#else
if (options.GenerateForwarders())
{
return MarshallingGenerators.Forwarder;
}

if (info.IsNativeReturnPosition && !info.IsManagedReturnPosition)
{
// Use marshaller for native HRESULT return / exception throwing
Expand Down Expand Up @@ -180,7 +183,7 @@ public static IMarshallingGenerator Create(
{
throw new MarshallingNotSupportedException(info, context);
}
return SafeHandle;
return new SafeHandleMarshaller(options);

// Marshalling in new model.
// Must go before the cases that do not explicitly check for marshalling info to support
Expand All @@ -204,15 +207,14 @@ public static IMarshallingGenerator Create(
return CreateStringMarshaller(info, context);

case { ManagedType: IArrayTypeSymbol { IsSZArray: true, ElementType: ITypeSymbol elementType } }:
return CreateArrayMarshaller(info, context, elementType);
return CreateArrayMarshaller(info, context, options, elementType);

case { ManagedType: { SpecialType: SpecialType.System_Void } }:
return Forwarder;

default:
throw new MarshallingNotSupportedException(info, context);
}
#endif
}

private static IMarshallingGenerator CreateCharMarshaller(TypePositionInfo info, StubCodeContext context)
Expand Down Expand Up @@ -303,7 +305,7 @@ private static IMarshallingGenerator CreateStringMarshaller(TypePositionInfo inf
throw new MarshallingNotSupportedException(info, context);
}

private static ExpressionSyntax GetNumElementsExpressionFromMarshallingInfo(TypePositionInfo info, StubCodeContext context)
private static ExpressionSyntax GetNumElementsExpressionFromMarshallingInfo(TypePositionInfo info, StubCodeContext context, AnalyzerConfigOptions options)
{
ExpressionSyntax numElementsExpression;
if (info.MarshallingAttributeInfo is not ArrayMarshalAsInfo marshalAsInfo)
Expand Down Expand Up @@ -338,7 +340,7 @@ private static ExpressionSyntax GetNumElementsExpressionFromMarshallingInfo(Type
else
{
var (managed, native) = context.GetIdentifiers(paramIndexInfo);
string identifier = Create(paramIndexInfo, context).UsesNativeIdentifier(paramIndexInfo, context) ? native : managed;
string identifier = Create(paramIndexInfo, context, options).UsesNativeIdentifier(paramIndexInfo, context) ? native : managed;
sizeParamIndexExpression = CastExpression(
PredefinedType(Token(SyntaxKind.IntKeyword)),
IdentifierName(identifier));
Expand All @@ -357,7 +359,7 @@ private static ExpressionSyntax GetNumElementsExpressionFromMarshallingInfo(Type
return numElementsExpression;
}

private static IMarshallingGenerator CreateArrayMarshaller(TypePositionInfo info, StubCodeContext context, ITypeSymbol elementType)
private static IMarshallingGenerator CreateArrayMarshaller(TypePositionInfo info, StubCodeContext context, AnalyzerConfigOptions options, ITypeSymbol elementType)
{
var elementMarshallingInfo = info.MarshallingAttributeInfo switch
{
Expand All @@ -367,12 +369,15 @@ private static IMarshallingGenerator CreateArrayMarshaller(TypePositionInfo info
_ => throw new MarshallingNotSupportedException(info, context)
};

var elementMarshaller = Create(TypePositionInfo.CreateForType(elementType, elementMarshallingInfo), new ArrayMarshallingCodeContext(StubCodeContext.Stage.Setup, string.Empty, context, false));
var elementMarshaller = Create(
TypePositionInfo.CreateForType(elementType, elementMarshallingInfo),
new ArrayMarshallingCodeContext(StubCodeContext.Stage.Setup, string.Empty, context, false),
options);
ExpressionSyntax numElementsExpression = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0));
if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In))
{
// In this case, we need a numElementsExpression supplied from metadata, so we'll calculate it here.
numElementsExpression = GetNumElementsExpressionFromMarshallingInfo(info, context);
numElementsExpression = GetNumElementsExpressionFromMarshallingInfo(info, context, options);
}

return elementMarshaller == Blittable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace Microsoft.Interop
{
internal class SafeHandleMarshaller : IMarshallingGenerator
{
private static readonly TypeSyntax NativeType = ParseTypeName("global::System.IntPtr");
private readonly AnalyzerConfigOptions options;

public SafeHandleMarshaller(AnalyzerConfigOptions options)
{
this.options = options;
}

public TypeSyntax AsNativeType(TypePositionInfo info)
{
Expand Down Expand Up @@ -83,7 +90,7 @@ public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeCont
IdentifierName(managedIdentifier),
InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
ParseName(TypeNames.System_Runtime_InteropServices_MarshalEx),
ParseName(TypeNames.MarshalEx(options)),
GenericName(Identifier("CreateSafeHandle"),
TypeArgumentList(SingletonSeparatedList(info.ManagedType.AsTypeSyntax())))),
ArgumentList())));
Expand All @@ -101,7 +108,7 @@ public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeCont
.WithInitializer(EqualsValueClause(
InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
ParseName(TypeNames.System_Runtime_InteropServices_MarshalEx),
ParseName(TypeNames.MarshalEx(options)),
GenericName(Identifier("CreateSafeHandle"),
TypeArgumentList(SingletonSeparatedList(info.ManagedType.AsTypeSyntax())))),
ArgumentList()))))));
Expand Down Expand Up @@ -160,7 +167,7 @@ public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeCont
StatementSyntax unmarshalStatement = ExpressionStatement(
InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
ParseTypeName(TypeNames.System_Runtime_InteropServices_MarshalEx),
ParseTypeName(TypeNames.MarshalEx(options)),
IdentifierName("SetHandle")),
ArgumentList(SeparatedList(
new []
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project>
<!--
Define all of the configuration options supported for the DllImportGenerator.
To use, set an MSBuild property with the name of the option to `true`.
See OptionsHelper.cs for more information on usage.
-->
<ItemGroup>
<!--
Use the System.Runtime.InteropServices.Marshal type instead of
the System.Runtime.InteropServices.MarshalEx type when emitting code.
-->
<CompilerVisibleProperty Include="DllImportGenerator_UseMarshalType" />
<!--
Generate a stub that forwards to a runtime implemented P/Invoke stub instead
of generating a stub that handles all of the marshalling.
-->
<CompilerVisibleProperty Include="DllImportGenerator_GenerateForwarders" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Microsoft.Interop
{
public static class OptionsHelper
{
public const string UseMarshalTypeOption = "build_property.DllImportGenerator_UseMarshalType";
public const string GenerateForwardersOption = "build_property.DllImportGenerator_GenerateForwarders";

private static bool GetBoolOption(this AnalyzerConfigOptions options, string key)
{
return options.TryGetValue(key, out string? value)
&& bool.TryParse(value, out bool result)
&& result;
}

internal static bool UseMarshalType(this AnalyzerConfigOptions options) => options.GetBoolOption(UseMarshalTypeOption);

internal static bool GenerateForwarders(this AnalyzerConfigOptions options) => options.GetBoolOption(GenerateForwardersOption);
}
}
Loading

0 comments on commit 9bc3120

Please sign in to comment.