Skip to content

Commit

Permalink
Add new proposed API to Ancillary.Interop (#81063)
Browse files Browse the repository at this point in the history
Updates the VTableStubGenerator to use the latest version of the proposed API.

Co-authored-by: Aaron Robinson <[email protected]>
Co-authored-by: Jeremy Koritzinsky <[email protected]>
  • Loading branch information
3 people authored Feb 17, 2023
1 parent 6ede02b commit 4dea84c
Show file tree
Hide file tree
Showing 53 changed files with 1,069 additions and 286 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M
ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.ManagedToUnmanaged),
ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.UnmanagedToManaged),
typeKeyOwner,
new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()));
new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()),
ParseTypeName(TypeNames.ComWrappersUnwrapper));
}

private static Diagnostic? GetDiagnosticIfInvalidTypeForGeneration(InterfaceDeclarationSyntax syntax, INamedTypeSymbol type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ public class Ids
isEnabledByDefault: true,
description: GetResourceString(nameof(SR.InvalidAttributedMethodDescription)));

public static readonly DiagnosticDescriptor InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttribute =
new DiagnosticDescriptor(
Ids.InvalidLibraryImportAttributeUsage,
GetResourceString(nameof(SR.InvalidVirtualMethodIndexAttributeUsage)),
GetResourceString(nameof(SR.InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage)),
Category,
DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: GetResourceString(nameof(SR.InvalidAttributedMethodDescription)));

public static readonly DiagnosticDescriptor InvalidStringMarshallingConfiguration =
new DiagnosticDescriptor(
Ids.InvalidLibraryImportAttributeUsage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ internal sealed record IncrementalMethodStubGenerationContext(
MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion)> ManagedToUnmanagedGeneratorFactory,
MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion)> UnmanagedToManagedGeneratorFactory,
ManagedTypeInfo TypeKeyOwner,
SequenceEqualImmutableArray<Diagnostic> Diagnostics);
SequenceEqualImmutableArray<Diagnostic> Diagnostics,
TypeSyntax UnwrapperSyntax);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace Microsoft.Interop
{
internal static class InlinedTypes
{
/// <summary>
/// Returns the ClassDeclarationSyntax for:
/// <code>
/// public sealed unsafe class ComWrappersUnwrapper : IUnmanagedObjectUnwrapper
/// {
/// public static object GetObjectForUnmanagedWrapper(void* ptr)
/// {
/// return ComWrappers.ComInterfaceDispatch.GetInstance<object>((ComWrappers.ComInterfaceDispatch*)ptr);
/// }
/// }
/// </code>
/// </summary>
public static ClassDeclarationSyntax ComWrappersUnwrapper { get; } = GetComWrappersUnwrapper();

public static ClassDeclarationSyntax GetComWrappersUnwrapper()
{
return ClassDeclaration("ComWrappersUnwrapper")
.AddModifiers(Token(SyntaxKind.SealedKeyword),
Token(SyntaxKind.UnsafeKeyword),
Token(SyntaxKind.StaticKeyword),
Token(SyntaxKind.FileKeyword))
.AddMembers(
MethodDeclaration(
PredefinedType(Token(SyntaxKind.ObjectKeyword)),
Identifier("GetComObjectForUnmanagedWrapper"))
.AddModifiers(Token(SyntaxKind.PublicKeyword),
Token(SyntaxKind.StaticKeyword))
.AddParameterListParameters(
Parameter(Identifier("ptr"))
.WithType(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword)))))
.WithBody(body: Body()));

static BlockSyntax Body()
{
var invocation = InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("ComWrappers"),
IdentifierName("ComInterfaceDispatch")),
GenericName(
Identifier("GetInstance"),
TypeArgumentList(
SeparatedList<SyntaxNode>(
new[] { PredefinedType(Token(SyntaxKind.ObjectKeyword)) })))))
.AddArgumentListArguments(
Argument(
null,
Token(SyntaxKind.None),
CastExpression(
PointerType(
QualifiedName(
IdentifierName("ComWrappers"),
IdentifierName("ComInterfaceDispatch"))),
IdentifierName("ptr"))));

return Block(ReturnStatement(invocation));
}
}

/// <summary>
/// <code>
/// file static class UnmanagedObjectUnwrapper
/// {
/// public static object GetObjectForUnmanagedWrapper<T>(void* ptr) where T : IUnmanagedObjectUnwrapper
/// {
/// return T.GetObjectForUnmanagedWrapper(ptr);
/// }
/// }
/// </code>
/// </summary>
public static ClassDeclarationSyntax UnmanagedObjectUnwrapper { get; } = GetUnmanagedObjectUnwrapper();

private static ClassDeclarationSyntax GetUnmanagedObjectUnwrapper()
{
const string tUnwrapper = "TUnwrapper";
return ClassDeclaration("UnmanagedObjectUnwrapper")
.AddModifiers(Token(SyntaxKind.FileKeyword),
Token(SyntaxKind.StaticKeyword))
.AddMembers(
MethodDeclaration(
PredefinedType(Token(SyntaxKind.ObjectKeyword)),
Identifier("GetObjectForUnmanagedWrapper"))
.AddModifiers(Token(SyntaxKind.PublicKeyword),
Token(SyntaxKind.StaticKeyword))
.AddTypeParameterListParameters(
TypeParameter(Identifier(tUnwrapper)))
.AddParameterListParameters(
Parameter(Identifier("ptr"))
.WithType(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword)))))
.AddConstraintClauses(TypeParameterConstraintClause(IdentifierName(tUnwrapper))
.AddConstraints(TypeConstraint(ParseTypeName(TypeNames.IUnmanagedObjectUnwrapper))))
.WithBody(body: Body()));

static BlockSyntax Body()
{
var invocation = InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("T"),
IdentifierName("GetObjectForUnmanagedWrapper")))
.AddArgumentListArguments(
Argument(
null,
Token(SyntaxKind.None),
IdentifierName("ptr")));

return Block(ReturnStatement(invocation));
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public ManagedToNativeVTableMethodGenerator(
if (implicitThis)
{
ImmutableArray<TypePositionInfo>.Builder newArgTypes = ImmutableArray.CreateBuilder<TypePositionInfo>(argTypes.Length + 1);
newArgTypes.Add(new TypePositionInfo(SpecialTypeInfo.IntPtr, NoMarshallingInfo.Instance)
newArgTypes.Add(new TypePositionInfo(new PointerTypeInfo("void*", "void*", false), NoMarshallingInfo.Instance)
{
InstanceIdentifier = NativeThisParameterIdentifier,
NativeIndex = 0
Expand Down Expand Up @@ -101,7 +101,7 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm
{
var setupStatements = new List<StatementSyntax>
{
// var (<thisParameter>, <virtualMethodTable>) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey<<containingTypeName>>();
// var (<thisParameter>, <virtualMethodTable>) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(typeof(<containingTypeName>));
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
Expand All @@ -121,12 +121,9 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm
CastExpression(
ParseTypeName(TypeNames.IUnmanagedVirtualMethodTableProvider),
ThisExpression())),
GenericName(
Identifier("GetVirtualMethodTableInfoForKey"),
TypeArgumentList(
SingletonSeparatedList(containingTypeName)))))
IdentifierName("GetVirtualMethodTableInfoForKey") ))
.WithArgumentList(
ArgumentList())))
ArgumentList(SeparatedList(new[]{ Argument(TypeOfExpression(containingTypeName)) })))))
};

GeneratedStatements statements = GeneratedStatements.Create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace Microsoft.Interop
{
internal sealed record NativeThisInfo : MarshallingInfo
{
public static readonly NativeThisInfo Instance = new();
}
internal sealed record NativeThisInfo(TypeSyntax UnwrapperType) : MarshallingInfo;

internal sealed class NativeToManagedThisMarshallerFactory : IMarshallingGeneratorFactory
{
Expand All @@ -30,27 +28,34 @@ private sealed class Marshaller : IMarshallingGenerator
public ManagedTypeInfo AsNativeType(TypePositionInfo info) => new PointerTypeInfo("void*", "void*", false);
public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeContext context)
{
Debug.Assert(info.MarshallingAttributeInfo is NativeThisInfo);
TypeSyntax unwrapperType = ((NativeThisInfo)info.MarshallingAttributeInfo).UnwrapperType;
if (context.CurrentStage != StubCodeContext.Stage.Unmarshal)
{
yield break;
}

(string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);

// <managed> = IUnmanagedVirtualMethodTableProvider.GetObjectForUnmanagedWrapper<<managedType>>(<native>);
// <managed> = (<managedType>)UnmanagedObjectUnwrapper.GetObjectFormUnmanagedWrapper<TUnmanagedUnwrapper>(<native>);
yield return ExpressionStatement(
AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
IdentifierName(managedIdentifier),
InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
ParseTypeName(TypeNames.IUnmanagedVirtualMethodTableProvider),
GenericName(Identifier("GetObjectForUnmanagedWrapper"),
TypeArgumentList(
SingletonSeparatedList(
info.ManagedType.Syntax)))),
ArgumentList(
SingletonSeparatedList(
Argument(IdentifierName(nativeIdentifier)))))));
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(managedIdentifier),
CastExpression(
info.ManagedType.Syntax,
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
ParseTypeName(TypeNames.UnmanagedObjectUnwrapper),
GenericName(Identifier("GetObjectForUnmanagedWrapper"))
.WithTypeArgumentList(
TypeArgumentList(
SingletonSeparatedList(
unwrapperType)))),
ArgumentList(
SingletonSeparatedList(
Argument(IdentifierName(nativeIdentifier))))))));
}

public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) => SignatureBehavior.NativeType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@
<data name="InterfaceTypeNotSupportedMessage" xml:space="preserve">
<value>Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'.</value>
</data>
<data name="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage" xml:space="preserve">
<value>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </value>
</data>
<data name="MethodNotDeclaredInAttributedInterfaceDescription" xml:space="preserve">
<value>All methods must be declared in the same partial definition of a 'GeneratedComInterface'-attributed interface type to ensure reliable calculation for virtual method table offsets.</value>
</data>
Expand All @@ -216,4 +219,4 @@
<data name="MethodNotDeclaredInAttributedInterfaceTitle" xml:space="preserve">
<value>Method is declared in different partial declaration than the 'GeneratedComInterface' attribute.</value>
</data>
</root>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
<target state="translated">Metoda {0} je obsažena v typu {1}, který není označen jako „partial“. Generování zdrojů volání P/Invoke bude metodu {0} ignorovat.</target>
<note />
</trans-unit>
<trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
<source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
<target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
<note />
</trans-unit>
<trans-unit id="InvalidAttributedMethodDescription">
<source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
<target state="translated">Metody označené atributem LibraryImportAttribute by měly být typu „static“, „partial“ a non-generic. Generování zdrojů volání P/Invoke bude ignorovat metody typu non-„static“, non-„partial“ a generic.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
<target state="translated">Die Methode \"{0}\" ist in einem Typ \"{1}\" enthalten, der nicht als \"partiell\" gekennzeichnet ist. Die P/Invoke-Quellgenerierung ignoriert die Methode \"{0}\".</target>
<note />
</trans-unit>
<trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
<source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
<target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
<note />
</trans-unit>
<trans-unit id="InvalidAttributedMethodDescription">
<source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
<target state="translated">Methoden, die mit \"LibraryImportAttribute\" gekennzeichnet sind, sollten \"statisch\", \"partiell\" und nicht generisch sein. Die P/Invoke-Quellgenerierung ignoriert Methoden, die nicht \"statisch\", nicht \"partiell\" oder generisch sind.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
<target state="translated">El método “{0}” está contenido en un tipo “{1}” que no está marcado como “partial”. La generación de código fuente P/Invoke omitirá el método “{0}”.</target>
<note />
</trans-unit>
<trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
<source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
<target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
<note />
</trans-unit>
<trans-unit id="InvalidAttributedMethodDescription">
<source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
<target state="translated">Los métodos marcados con “LibraryImportAttribute” deben ser “static”, “partial” y no genéricos. La generación de código fuente P/Invoke omitirá los métodos que no sean “static”, “partial” ni genéricos.</target>
Expand Down
Loading

0 comments on commit 4dea84c

Please sign in to comment.