Skip to content

Commit

Permalink
Merge pull request #1114 from microsoft/comhelpersNonPartial
Browse files Browse the repository at this point in the history
Allow `ComHelpers` class to be non-partially declared by compilation
  • Loading branch information
AArnott committed Jan 12, 2024
2 parents bb31419 + 3e163e9 commit e0351f9
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/Microsoft.Windows.CsWin32/Generator.Handle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public partial class Generator
return safeHandleType;
}

if (this.FindTypeSymbolsIfAlreadyAvailable($"{this.Namespace}.{safeHandleType}").Count > 0)
if (this.FindTypeSymbolIfAlreadyAvailable($"{this.Namespace}.{safeHandleType}") is not null)
{
return safeHandleType;
}
Expand Down
40 changes: 31 additions & 9 deletions src/Microsoft.Windows.CsWin32/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -867,12 +867,24 @@ internal void RequestComHelpers(Context context)
{
if (this.IsWin32Sdk)
{
this.RequestInteropType("Windows.Win32.Foundation", "HRESULT", context);
this.volatileCode.GenerateSpecialType("ComHelpers", () => this.volatileCode.AddSpecialType("ComHelpers", this.comHelperClass));
if (!this.IsTypeAlreadyFullyDeclared($"{this.Namespace}.{this.comHelperClass.Identifier.ValueText}"))
{
this.RequestInteropType("Windows.Win32.Foundation", "HRESULT", context);
this.volatileCode.GenerateSpecialType("ComHelpers", () => this.volatileCode.AddSpecialType("ComHelpers", this.comHelperClass));
}

if (this.IsFeatureAvailable(Feature.InterfaceStaticMembers) && !context.AllowMarshaling)
{
this.volatileCode.GenerateSpecialType("IVTable", () => this.volatileCode.AddSpecialType("IVTable", IVTableInterface));
this.volatileCode.GenerateSpecialType("IVTable`2", () => this.volatileCode.AddSpecialType("IVTable`2", IVTableGenericInterface));
if (!this.IsTypeAlreadyFullyDeclared($"{this.Namespace}.{IVTableInterface.Identifier.ValueText}"))
{
this.volatileCode.GenerateSpecialType("IVTable", () => this.volatileCode.AddSpecialType("IVTable", IVTableInterface));
}

if (!this.IsTypeAlreadyFullyDeclared($"{this.Namespace}.{IVTableGenericInterface.Identifier.ValueText}`2"))
{
this.volatileCode.GenerateSpecialType("IVTable`2", () => this.volatileCode.AddSpecialType("IVTable`2", IVTableGenericInterface));
}

if (!this.TryGenerate("IUnknown", default))
{
throw new GenerationFailedException("Unable to generate IUnknown.");
Expand Down Expand Up @@ -1058,10 +1070,7 @@ internal void GetBaseTypeInfo(TypeDefinition typeDef, out StringHandle baseTypeN
string ns = $"{this.Namespace}.{subNamespace}";
fullyQualifiedName = $"{ns}.{specialName}";

// Skip if the compilation already defines this type or can access it from elsewhere.
// But if we have more than one match, the compiler won't be able to resolve our type references.
// In such a case, we'll prefer to just declare our own local symbol.
if (this.FindTypeSymbolsIfAlreadyAvailable(fullyQualifiedName).Count == 1)
if (this.IsTypeAlreadyFullyDeclared(fullyQualifiedName))
{
// The type already exists either in this project or a referenced one.
return null;
Expand Down Expand Up @@ -1183,6 +1192,19 @@ private bool TryGetRenamedMethod(string methodName, [NotNullWhen(true)] out stri
return false;
}

/// <summary>
/// Checks whether a type with the given name is already defined in the compilation
/// such that we must (or should) skip generating it ourselves.
/// </summary>
/// <param name="fullyQualifiedMetadataName">The fully-qualified metadata name of the type.</param>
/// <returns><see langword="true"/> if the type should <em>not</em> be emitted; <see langword="false" /> if the type is not already declared in the compilation.</returns>
/// <remarks>
/// Skip if the compilation already defines this type or can access it from elsewhere.
/// But if we have more than one match, the compiler won't be able to resolve our type references.
/// In such a case, we'll prefer to just declare our own local symbol.
/// </remarks>
private bool IsTypeAlreadyFullyDeclared(string fullyQualifiedMetadataName) => this.FindTypeSymbolsIfAlreadyAvailable(fullyQualifiedMetadataName).Count == 1;

private ISymbol? FindTypeSymbolIfAlreadyAvailable(string fullyQualifiedMetadataName) => this.FindTypeSymbolsIfAlreadyAvailable(fullyQualifiedMetadataName).FirstOrDefault();

private IReadOnlyList<ISymbol> FindTypeSymbolsIfAlreadyAvailable(string fullyQualifiedMetadataName)
Expand Down Expand Up @@ -1264,7 +1286,7 @@ private IReadOnlyList<ISymbol> FindTypeSymbolsIfAlreadyAvailable(string fullyQua
// Skip if the compilation already defines this type or can access it from elsewhere.
// But if we have more than one match, the compiler won't be able to resolve our type references.
// In such a case, we'll prefer to just declare our own local symbol.
if (this.FindTypeSymbolsIfAlreadyAvailable(fullyQualifiedName).Count == 1)
if (this.IsTypeAlreadyFullyDeclared(fullyQualifiedName))
{
// The type already exists either in this project or a referenced one.
return null;
Expand Down

0 comments on commit e0351f9

Please sign in to comment.