Skip to content

Commit

Permalink
Merge pull request #1000 from microsoft/fix999
Browse files Browse the repository at this point in the history
Fix generation of APIs from ServiceFabric winmd
  • Loading branch information
AArnott authored Jul 27, 2023
2 parents dc807e7 + b34ac8c commit 5d84f15
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 8 deletions.
18 changes: 11 additions & 7 deletions src/Microsoft.Windows.CsWin32/Generator.Com.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ private TypeDeclarationSyntax DeclareInterfaceAsStruct(TypeDefinitionHandle type
IdentifierNameSyntax hrLocal = IdentifierName("__hr");
StatementSyntax returnSOK = ReturnStatement(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, HresultTypeSyntax, IdentifierName("S_OK")));

this.MainGenerator.RequestInteropType("Windows.Win32.Foundation", "HRESULT", context);

// It is imperative that we generate methods for all base interfaces as well, ahead of any implemented by *this* interface.
var allMethods = new List<QualifiedMethodDefinitionHandle>();
while (!baseTypes.IsEmpty)
Expand All @@ -134,11 +136,13 @@ private TypeDeclarationSyntax DeclareInterfaceAsStruct(TypeDefinitionHandle type
allMethods.AddRange(typeDef.GetMethods().Select(m => new QualifiedMethodDefinitionHandle(this, m)));
int methodCounter = 0;
HashSet<string> helperMethodsInStruct = new();
ISet<string> declaredProperties = this.GetDeclarableProperties(
allMethods.Select(qh => qh.Reader.GetMethodDefinition(qh.MethodHandle)),
originalIfaceName,
allowNonConsecutiveAccessors: true,
context);
HashSet<string> declaredProperties = new(StringComparer.Ordinal);
declaredProperties.UnionWith(
from method in allMethods
group method by method.Generator into methodsByMetadata
let methodDefs = methodsByMetadata.Select(qh => qh.Reader.GetMethodDefinition(qh.MethodHandle))
from property in methodsByMetadata.Key.GetDeclarableProperties(methodDefs, originalIfaceName, allowNonConsecutiveAccessors: true, context)
select property);
ISet<string>? ifaceDeclaredProperties = ccwThisParameter is not null ? this.GetDeclarableProperties(allMethods.Select(qh => qh.Reader.GetMethodDefinition(qh.MethodHandle)), originalIfaceName, allowNonConsecutiveAccessors: false, context) : null;

foreach (QualifiedMethodDefinitionHandle methodDefHandle in allMethods)
Expand Down Expand Up @@ -189,7 +193,7 @@ private TypeDeclarationSyntax DeclareInterfaceAsStruct(TypeDefinitionHandle type

// We can declare this method as a property accessor if it represents a property.
// We must also confirm that the property type is the same in both cases, because sometimes they aren't (e.g. IUIAutomationProxyFactoryEntry.ClassName).
if (this.TryGetPropertyAccessorInfo(methodDefinition.Method, originalIfaceName, context, out IdentifierNameSyntax? propertyName, out SyntaxKind? accessorKind, out TypeSyntax? propertyType) &&
if (methodDefinition.Generator.TryGetPropertyAccessorInfo(methodDefinition.Method, originalIfaceName, context, out IdentifierNameSyntax? propertyName, out SyntaxKind? accessorKind, out TypeSyntax? propertyType) &&
declaredProperties.Contains(propertyName.Identifier.ValueText))
{
StatementSyntax ThrowOnHRFailure(ExpressionSyntax hrExpression) => ExpressionStatement(InvocationExpression(
Expand Down Expand Up @@ -257,7 +261,7 @@ StatementSyntax ThrowOnHRFailure(ExpressionSyntax hrExpression) => ExpressionSta
else
{
BlockSyntax body;
bool preserveSig = this.UsePreserveSigForComMethod(methodDefinition.Method, signature, ifaceName.Identifier.ValueText, methodName);
bool preserveSig = methodDefinition.Generator.UsePreserveSigForComMethod(methodDefinition.Method, signature, ifaceName.Identifier.ValueText, methodName);
if (preserveSig)
{
// return ...
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.Windows.CsWin32/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ internal Generator MainGenerator

private bool WideCharOnly => this.options.WideCharOnly;

private string Namespace => this.InputAssemblyName;
private string Namespace => this.MetadataIndex.CommonNamespace;

private SyntaxKind Visibility => this.options.Public ? SyntaxKind.PublicKeyword : SyntaxKind.InternalKeyword;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This folder contains winmd files obtained from other sources which we use for testing.

Metadata | Source
--|--
ServiceFabric.winmd | [youyuanwu/fabric-metadata](https://github.com/youyuanwu/fabric-metadata/raw/a1bcca6ad6f6a772c9e5ff4bdba80ae5e5f24cfc/.windows/winmd/ServiceFabric.winmd)
Binary file not shown.
1 change: 1 addition & 0 deletions test/Microsoft.Windows.CsWin32.Tests/GeneratorTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public abstract class GeneratorTestBase : IDisposable, IAsyncLifetime
protected static readonly string WdkMetadataPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!, "Windows.Wdk.winmd");
protected static readonly string[] DefaultMetadataPaths = new[] { MetadataPath, WdkMetadataPath };
////protected static readonly string DiaMetadataPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!, "Microsoft.Dia.winmd");
protected static readonly string ServiceFabricMetadataPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!, "ExternalMetadata", "ServiceFabric.winmd");
protected static readonly string ApiDocsPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location!)!, "apidocs.msgpack");

protected readonly ITestOutputHelper logger;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
<None Include="@(ProjectionDocs)">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="ExternalMetadata\*.winmd">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
Expand Down
19 changes: 19 additions & 0 deletions test/Microsoft.Windows.CsWin32.Tests/MultiMetadataTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

public class MultiMetadataTests : GeneratorTestBase
{
public MultiMetadataTests(ITestOutputHelper logger)
: base(logger)
{
}

[Theory, PairwiseData]
public void BasicServiceFabric(bool allowMarshaling)
{
this.generator = this.CreateSuperGenerator(DefaultMetadataPaths.Concat(new[] { ServiceFabricMetadataPath }).ToArray(), DefaultTestGeneratorOptions with { AllowMarshaling = allowMarshaling });
Assert.True(this.generator.TryGenerate("IFabricStringResult", CancellationToken.None));
this.CollectGeneratedCode(this.generator);
this.AssertNoDiagnostics();
}
}

0 comments on commit 5d84f15

Please sign in to comment.