Skip to content

Commit

Permalink
Merge pull request #944 from microsoft/prepareFor395
Browse files Browse the repository at this point in the history
Prepare for multi-metadata input to source generator
  • Loading branch information
AArnott committed May 25, 2023
2 parents 73ae8da + c679380 commit ed29c9e
Show file tree
Hide file tree
Showing 27 changed files with 463 additions and 311 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ dotnet_diagnostic.DOC200.severity = warning
dotnet_diagnostic.DOC202.severity = warning

# CA1062: Validate arguments of public methods
dotnet_diagnostic.CA1062.severity = warning
dotnet_diagnostic.CA1062.severity = suggestion

[*.sln]
indent_style = tab
13 changes: 1 addition & 12 deletions Microsoft.Windows.CsWin32.sln
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.CsWin32",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Windows.CsWin32.Tests", "test\Microsoft.Windows.CsWin32.Tests\Microsoft.Windows.CsWin32.Tests.csproj", "{0129FE6E-3480-408A-BF40-9E6343CDB06C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Win32MetaGeneration", "src\Win32MetaGeneration\Win32MetaGeneration.csproj", "{6638957D-09ED-47C1-86B9-5D2DFD0FE625}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenerationSandbox.Tests", "test\GenerationSandbox.Tests\GenerationSandbox.Tests.csproj", "{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpellChecker", "test\SpellChecker\SpellChecker.csproj", "{744BE74F-8C4A-49E8-9683-52D987224285}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinRTInteropTest", "test\WinRTInteropTest\WinRTInteropTest.csproj", "{0E067B66-C2EC-4106-87D2-5310CFCDC5B8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenerationSandbox.Unmarshalled.Tests", "test\GenerationSandbox.Unmarshalled.Tests\GenerationSandbox.Unmarshalled.Tests.csproj", "{3D303454-7DB0-4F9F-BD9E-07F09D3C70E3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenerationSandbox.Unmarshalled.Tests", "test\GenerationSandbox.Unmarshalled.Tests\GenerationSandbox.Unmarshalled.Tests.csproj", "{3D303454-7DB0-4F9F-BD9E-07F09D3C70E3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -69,14 +67,6 @@ Global
{0129FE6E-3480-408A-BF40-9E6343CDB06C}.Release|Any CPU.Build.0 = Release|Any CPU
{0129FE6E-3480-408A-BF40-9E6343CDB06C}.Release|NonWindows.ActiveCfg = Release|Any CPU
{0129FE6E-3480-408A-BF40-9E6343CDB06C}.Release|NonWindows.Build.0 = Release|Any CPU
{6638957D-09ED-47C1-86B9-5D2DFD0FE625}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6638957D-09ED-47C1-86B9-5D2DFD0FE625}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6638957D-09ED-47C1-86B9-5D2DFD0FE625}.Debug|NonWindows.ActiveCfg = Debug|Any CPU
{6638957D-09ED-47C1-86B9-5D2DFD0FE625}.Debug|NonWindows.Build.0 = Debug|Any CPU
{6638957D-09ED-47C1-86B9-5D2DFD0FE625}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6638957D-09ED-47C1-86B9-5D2DFD0FE625}.Release|Any CPU.Build.0 = Release|Any CPU
{6638957D-09ED-47C1-86B9-5D2DFD0FE625}.Release|NonWindows.ActiveCfg = Release|Any CPU
{6638957D-09ED-47C1-86B9-5D2DFD0FE625}.Release|NonWindows.Build.0 = Release|Any CPU
{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3}.Debug|NonWindows.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -114,7 +104,6 @@ Global
GlobalSection(NestedProjects) = preSolution
{E3E96466-44B6-41AF-BBC8-9D30183ED8A9} = {9E154A29-1796-4B85-BD81-B6A385D8FF71}
{0129FE6E-3480-408A-BF40-9E6343CDB06C} = {36CCE840-6FE5-4DB9-A8D5-8CF3CB6D342A}
{6638957D-09ED-47C1-86B9-5D2DFD0FE625} = {9E154A29-1796-4B85-BD81-B6A385D8FF71}
{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3} = {36CCE840-6FE5-4DB9-A8D5-8CF3CB6D342A}
{744BE74F-8C4A-49E8-9683-52D987224285} = {36CCE840-6FE5-4DB9-A8D5-8CF3CB6D342A}
{0E067B66-C2EC-4106-87D2-5310CFCDC5B8} = {36CCE840-6FE5-4DB9-A8D5-8CF3CB6D342A}
Expand Down
5 changes: 1 addition & 4 deletions src/Microsoft.Windows.CsWin32/Generator.Constant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ namespace Microsoft.Windows.CsWin32;

public partial class Generator
{
/// <summary>
/// Generates a projection of all constants.
/// </summary>
/// <param name="cancellationToken">A cancellation token.</param>
/// <inheritdoc/>
public void GenerateAllConstants(CancellationToken cancellationToken)
{
foreach (FieldDefinitionHandle fieldDefHandle in this.MetadataIndex.Apis.SelectMany(api => this.Reader.GetTypeDefinition(api).GetFields()))
Expand Down
18 changes: 16 additions & 2 deletions src/Microsoft.Windows.CsWin32/Generator.Delegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ public partial class Generator
{
internal static bool IsUntypedDelegate(MetadataReader reader, TypeDefinition typeDef) => reader.StringComparer.Equals(typeDef.Name, "PROC") || reader.StringComparer.Equals(typeDef.Name, "FARPROC");

internal FunctionPointerTypeSyntax FunctionPointer(QualifiedTypeDefinition delegateType)
{
if (delegateType.Generator != this)
{
FunctionPointerTypeSyntax? result = null;
delegateType.Generator.volatileCode.GenerationTransaction(() => result = delegateType.Generator.FunctionPointer(delegateType.Definition));
return result!;
}
else
{
return this.FunctionPointer(delegateType.Definition);
}
}

internal FunctionPointerTypeSyntax FunctionPointer(TypeDefinition delegateType)
{
CustomAttribute ufpAtt = this.FindAttribute(delegateType.GetCustomAttributes(), SystemRuntimeInteropServices, nameof(UnmanagedFunctionPointerAttribute))!.Value;
Expand Down Expand Up @@ -130,9 +144,9 @@ private FunctionPointerTypeSyntax FunctionPointer(MethodDefinition methodDefinit

private FunctionPointerParameterSyntax TranslateDelegateToFunctionPointer(TypeHandleInfo parameterTypeInfo, CustomAttributeHandleCollection? customAttributeHandles)
{
if (this.IsDelegateReference(parameterTypeInfo, out TypeDefinition delegateTypeDef))
if (this.IsDelegateReference(parameterTypeInfo, out QualifiedTypeDefinition delegateTypeDef))
{
return FunctionPointerParameter(this.FunctionPointer(delegateTypeDef));
return FunctionPointerParameter(delegateTypeDef.Generator.FunctionPointer(delegateTypeDef.Definition));
}

return FunctionPointerParameter(parameterTypeInfo.ToTypeSyntax(this.functionPointerTypeSettings, customAttributeHandles).GetUnmarshaledType());
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.Windows.CsWin32/Generator.Enum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Microsoft.Windows.CsWin32;

public partial class Generator
{
/// <inheritdoc cref="MetadataIndex.TryGetEnumName(MetadataReader, string, out string?)"/>
/// <inheritdoc/>
public bool TryGetEnumName(string enumValueName, [NotNullWhen(true)] out string? declaringEnum) => this.MetadataIndex.TryGetEnumName(this.Reader, enumValueName, out declaringEnum);

private EnumDeclarationSyntax DeclareEnum(TypeDefinition typeDef)
Expand Down
12 changes: 2 additions & 10 deletions src/Microsoft.Windows.CsWin32/Generator.Extern.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ namespace Microsoft.Windows.CsWin32;

public partial class Generator
{
/// <summary>
/// Generates a projection of all extern methods and their supporting types.
/// </summary>
/// <param name="cancellationToken">A cancellation token.</param>
/// <inheritdoc/>
public void GenerateAllExternMethods(CancellationToken cancellationToken)
{
foreach (MethodDefinitionHandle methodHandle in this.MetadataIndex.Apis.SelectMany(api => this.Reader.GetTypeDefinition(api).GetMethods()))
Expand Down Expand Up @@ -94,12 +91,7 @@ public bool TryGenerateAllExternMethods(string moduleName, CancellationToken can
return successful;
}

/// <summary>
/// Generate code for the named extern method, if it is recognized.
/// </summary>
/// <param name="possiblyQualifiedName">The name of the extern method, optionally qualified with a namespace.</param>
/// <param name="preciseApi">Receives the canonical API names that <paramref name="possiblyQualifiedName"/> matched on.</param>
/// <returns><see langword="true"/> if a match was found and the extern method generated; otherwise <see langword="false"/>.</returns>
/// <inheritdoc/>
public bool TryGenerateExternMethod(string possiblyQualifiedName, out IReadOnlyList<string> preciseApi)
{
if (possiblyQualifiedName is null)
Expand Down
6 changes: 6 additions & 0 deletions src/Microsoft.Windows.CsWin32/Generator.Features.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ private void DeclareUnscopedRefAttributeIfNecessary()
return;
}

if (!this.IsWin32Sdk)
{
this.MainGenerator.volatileCode.GenerationTransaction(() => this.MainGenerator.DeclareUnscopedRefAttributeIfNecessary());
return;
}

const string name = "UnscopedRefAttribute";
this.volatileCode.GenerateSpecialType(name, delegate
{
Expand Down
6 changes: 3 additions & 3 deletions src/Microsoft.Windows.CsWin32/Generator.Handle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,16 +185,16 @@ public partial class Generator
{
case "NTSTATUS":
this.TryGenerateConstantOrThrow("STATUS_SUCCESS");
ExpressionSyntax statusSuccess = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ParseName("winmdroot.Foundation.NTSTATUS"), IdentifierName("STATUS_SUCCESS"));
ExpressionSyntax statusSuccess = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ParseName("global::Windows.Win32.Foundation.NTSTATUS"), IdentifierName("STATUS_SUCCESS"));
releaseInvocation = BinaryExpression(SyntaxKind.EqualsExpression, releaseInvocation, statusSuccess);
break;
case "HRESULT":
this.TryGenerateConstantOrThrow("S_OK");
ExpressionSyntax ok = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ParseName("winmdroot.Foundation.HRESULT"), IdentifierName("S_OK"));
ExpressionSyntax ok = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ParseName("global::Windows.Win32.Foundation.HRESULT"), IdentifierName("S_OK"));
releaseInvocation = BinaryExpression(SyntaxKind.EqualsExpression, releaseInvocation, ok);
break;
case "WIN32_ERROR":
ExpressionSyntax noerror = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ParseName("winmdroot.Foundation.WIN32_ERROR"), IdentifierName("NO_ERROR"));
ExpressionSyntax noerror = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ParseName("global::Windows.Win32.Foundation.WIN32_ERROR"), IdentifierName("NO_ERROR"));
releaseInvocation = BinaryExpression(SyntaxKind.EqualsExpression, releaseInvocation, noerror);
break;
case "HGLOBAL":
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.Windows.CsWin32/Generator.InlineArrays.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public partial class Generator
{
private (TypeSyntax FieldType, SyntaxList<MemberDeclarationSyntax> AdditionalMembers, AttributeSyntax? MarshalAsAttribute) DeclareFixedLengthArrayStruct(FieldDefinition fieldDef, CustomAttributeHandleCollection customAttributes, TypeHandleInfo fieldTypeHandleInfo, ArrayTypeSyntax arrayType, Context context)
{
if (this.options.AllowMarshaling && this.IsManagedType(fieldTypeHandleInfo))
if (context.AllowMarshaling && this.IsManagedType(fieldTypeHandleInfo))
{
ArrayTypeSyntax ranklessArray = arrayType.WithRankSpecifiers(new SyntaxList<ArrayRankSpecifierSyntax>(ArrayRankSpecifier()));
AttributeSyntax marshalAs = MarshalAs(UnmanagedType.ByValArray, sizeConst: arrayType.RankSpecifiers[0].Sizes[0]);
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.Windows.CsWin32/Generator.Invariants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public partial class Generator

private static readonly Dictionary<string, MethodDeclarationSyntax> PInvokeHelperMethods;
private static readonly ClassDeclarationSyntax ComHelperClass;
private static readonly Dictionary<string, MethodDeclarationSyntax> PInvokeMacros;
private static readonly Dictionary<string, MethodDeclarationSyntax> Win32SdkMacros;

private static readonly string AutoGeneratedHeader = @"// ------------------------------------------------------------------------------
// <auto-generated>
Expand Down Expand Up @@ -312,7 +312,7 @@ public partial class Generator
/// <summary>
/// Gets the set of macros that can be generated.
/// </summary>
public static IEnumerable<string> AvailableMacros => PInvokeMacros.Keys;
public static IEnumerable<string> AvailableMacros => Win32SdkMacros.Keys;

/// <summary>
/// Gets a map of interop APIs that should never be generated, whether marshaling is allowed or not, and messages to emit in diagnostics if these APIs are ever directly requested.
Expand Down
63 changes: 35 additions & 28 deletions src/Microsoft.Windows.CsWin32/Generator.MetadataHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ internal bool IsManagedType(TypeHandleInfo typeHandleInfo)
else if (elementType is HandleTypeHandleInfo { Handle: { Kind: HandleKind.TypeReference } typeRefHandle } handleElement)
{
var trh = (TypeReferenceHandle)typeRefHandle;
if (this.TryGetTypeDefHandle(trh, out TypeDefinitionHandle tdr))
if (this.TryGetTypeDefHandle(trh, out QualifiedTypeDefinitionHandle qtdr))
{
return this.IsManagedType(tdr);
return qtdr.Generator.IsManagedType(qtdr.DefinitionHandle);
}

// If the type comes from an external assembly, assume that structs are blittable and anything else is not.
Expand Down Expand Up @@ -228,7 +228,7 @@ private static bool IsAnsiFunction(string methodName)
return false;
}

private bool IsDelegateReference(TypeHandleInfo typeHandleInfo, out TypeDefinition delegateTypeDef)
private bool IsDelegateReference(TypeHandleInfo typeHandleInfo, out QualifiedTypeDefinition delegateTypeDef)
{
if (typeHandleInfo is PointerTypeHandleInfo { ElementType: HandleTypeHandleInfo handleInfo })
{
Expand All @@ -243,22 +243,22 @@ private bool IsDelegateReference(TypeHandleInfo typeHandleInfo, out TypeDefiniti
return false;
}

private bool IsDelegateReference(HandleTypeHandleInfo typeHandleInfo, out TypeDefinition delegateTypeDef)
private bool IsDelegateReference(HandleTypeHandleInfo typeHandleInfo, out QualifiedTypeDefinition delegateTypeDef)
{
if (typeHandleInfo.Handle.Kind == HandleKind.TypeDefinition)
{
var tdh = (TypeDefinitionHandle)typeHandleInfo.Handle;
delegateTypeDef = this.Reader.GetTypeDefinition(tdh);
return this.IsDelegate(delegateTypeDef);
delegateTypeDef = new(this, this.Reader.GetTypeDefinition(tdh));
return this.IsDelegate(delegateTypeDef.Definition);
}

if (typeHandleInfo.Handle.Kind == HandleKind.TypeReference)
{
var trh = (TypeReferenceHandle)typeHandleInfo.Handle;
if (this.TryGetTypeDefHandle(trh, out TypeDefinitionHandle tdh))
if (this.TryGetTypeDefHandle(trh, out QualifiedTypeDefinitionHandle qtdh))
{
delegateTypeDef = this.Reader.GetTypeDefinition(tdh);
return this.IsDelegate(delegateTypeDef);
delegateTypeDef = qtdh.Resolve();
return qtdh.Generator.IsDelegate(delegateTypeDef.Definition);
}
}

Expand Down Expand Up @@ -370,14 +370,14 @@ private bool IsManagedType(TypeDefinitionHandle typeDefinitionHandle)
}
else if (elementType is HandleTypeHandleInfo { Handle: { Kind: HandleKind.TypeDefinition } fieldTypeDefHandle })
{
if (TestFieldAndHandleCycle((TypeDefinitionHandle)fieldTypeDefHandle) is true)
if (TestFieldAndHandleCycle(new(this, (TypeDefinitionHandle)fieldTypeDefHandle)) is true)
{
return true;
}
}
else if (elementType is HandleTypeHandleInfo { Handle: { Kind: HandleKind.TypeReference } fieldTypeRefHandle })
{
if (this.TryGetTypeDefHandle((TypeReferenceHandle)fieldTypeRefHandle, out TypeDefinitionHandle tdr) && TestFieldAndHandleCycle(tdr) is true)
if (this.TryGetTypeDefHandle((TypeReferenceHandle)fieldTypeRefHandle, out QualifiedTypeDefinitionHandle qtdr) && TestFieldAndHandleCycle(qtdr) is true)
{
return true;
}
Expand All @@ -387,26 +387,33 @@ private bool IsManagedType(TypeDefinitionHandle typeDefinitionHandle)
throw new GenerationFailedException("Unrecognized type.");
}

bool? TestFieldAndHandleCycle(TypeDefinitionHandle tdh)
bool? TestFieldAndHandleCycle(QualifiedTypeDefinitionHandle qtdh)
{
bool? result = Helper(tdh);
switch (result)
if (qtdh.Generator == this)
{
case true:
this.managedTypesCheck.Add(typeDefinitionHandle, true);
break;
case null:
cycleFixups ??= new();
if (!cycleFixups.TryGetValue(tdh, out var list))
{
cycleFixups.Add(tdh, list = new());
}

list.Add(typeDefinitionHandle);
break;
bool? result = Helper(qtdh.DefinitionHandle);
switch (result)
{
case true:
this.managedTypesCheck.Add(typeDefinitionHandle, true);
break;
case null:
cycleFixups ??= new();
if (!cycleFixups.TryGetValue(qtdh.DefinitionHandle, out var list))
{
cycleFixups.Add(qtdh.DefinitionHandle, list = new());
}

list.Add(typeDefinitionHandle);
break;
}

return result;
}
else
{
return qtdh.Generator.IsManagedType(qtdh.DefinitionHandle);
}

return result;
}
}
catch (Exception ex)
Expand Down
Loading

0 comments on commit ed29c9e

Please sign in to comment.