forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split the MarshalAsParser into two classes (dotnet#93038)
- Loading branch information
1 parent
e66bc8a
commit 55be11c
Showing
4 changed files
with
138 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
...opServices/gen/Microsoft.Interop.SourceGeneration/MarshalAsWithCustomMarshallersParser.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Runtime.InteropServices; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Microsoft.Interop | ||
{ | ||
/// <summary> | ||
/// This class suppports parsing a System.Runtime.InteropServices.MarshalAsAttribute into either a <see cref="MarshalAsInfo"/> or a <see cref="NativeMarshallingAttributeInfo"/> | ||
/// if the marshalling is implemented with a custom marshaller in the framework. | ||
/// </summary> | ||
public sealed class MarshalAsWithCustomMarshallersParser : IMarshallingInfoAttributeParser | ||
{ | ||
private readonly Compilation _compilation; | ||
private readonly GeneratorDiagnosticsBag _diagnostics; | ||
private readonly IMarshallingInfoAttributeParser _marshalAsAttributeParser; | ||
|
||
/// <summary> | ||
/// Create a new instance of <see cref="MarshalAsWithCustomMarshallersParser"/>. | ||
/// </summary> | ||
/// <param name="compilation">The compilation that the attributes are defined within.</param> | ||
/// <param name="diagnostics">The diagnostics bag to which to report diagnostics.</param> | ||
/// <param name="marshalAsAttributeParser">The parser that will do basic parsing of a MarshalAsAttribute into a <see cref="MarshalAsInfo"/> element.</param> | ||
public MarshalAsWithCustomMarshallersParser(Compilation compilation, GeneratorDiagnosticsBag diagnostics, IMarshallingInfoAttributeParser marshalAsAttributeParser) | ||
{ | ||
_compilation = compilation; | ||
_diagnostics = diagnostics; | ||
_marshalAsAttributeParser = marshalAsAttributeParser; | ||
} | ||
|
||
public bool CanParseAttributeType(INamedTypeSymbol attributeType) => attributeType.ToDisplayString() == TypeNames.System_Runtime_InteropServices_MarshalAsAttribute; | ||
|
||
MarshallingInfo? IMarshallingInfoAttributeParser.ParseAttribute(AttributeData attributeData, ITypeSymbol type, int indirectionDepth, UseSiteAttributeProvider useSiteAttributes, GetMarshallingInfoCallback marshallingInfoCallback) | ||
{ | ||
var marshalAsInfo = (MarshalAsInfo)_marshalAsAttributeParser.ParseAttribute(attributeData, type, indirectionDepth, useSiteAttributes, marshallingInfoCallback); | ||
|
||
// We'll support the UnmanagedType.Interface option, but we'll explicitly | ||
// leave ComImport types with the MarshalAs info instead of the custom marshaller | ||
// as they will not work as expected unless they are migrated to [GeneratedComInterface]. | ||
if (marshalAsInfo.UnmanagedType == UnmanagedType.Interface) | ||
{ | ||
return type is INamedTypeSymbol { IsComImport: true } | ||
? marshalAsInfo | ||
: ComInterfaceMarshallingInfoProvider.CreateComInterfaceMarshallingInfo(_compilation, type); | ||
} | ||
|
||
if (marshalAsInfo is MarshalAsArrayInfo arrayInfo) | ||
{ | ||
if (type is not IArrayTypeSymbol { ElementType: ITypeSymbol elementType }) | ||
{ | ||
_diagnostics.ReportConfigurationNotSupported(attributeData, nameof(UnmanagedType), arrayInfo.UnmanagedType.ToString()); | ||
return NoMarshallingInfo.Instance; | ||
} | ||
|
||
MarshallingInfo elementMarshallingInfo = NoMarshallingInfo.Instance; | ||
if (arrayInfo.ArraySubType != (UnmanagedType)SizeAndParamIndexInfo.UnspecifiedConstSize) | ||
{ | ||
if (elementType.SpecialType == SpecialType.System_String) | ||
{ | ||
elementMarshallingInfo = CreateStringMarshallingInfo(elementType, new MarshalAsScalarInfo(arrayInfo.ArraySubType, arrayInfo.CharEncoding)); | ||
} | ||
else if (arrayInfo.ArraySubType == UnmanagedType.Interface && elementType is not INamedTypeSymbol { IsComImport: true }) | ||
{ | ||
elementMarshallingInfo = ComInterfaceMarshallingInfoProvider.CreateComInterfaceMarshallingInfo(_compilation, elementType); | ||
} | ||
else | ||
{ | ||
elementMarshallingInfo = new MarshalAsScalarInfo(arrayInfo.ArraySubType, arrayInfo.CharEncoding); | ||
} | ||
} | ||
else | ||
{ | ||
elementMarshallingInfo = marshallingInfoCallback(elementType, useSiteAttributes, indirectionDepth + 1); | ||
} | ||
|
||
CountInfo countInfo = NoCountInfo.Instance; | ||
|
||
if (useSiteAttributes.TryGetUseSiteAttributeInfo(indirectionDepth, out UseSiteAttributeData useSiteAttributeData)) | ||
{ | ||
countInfo = useSiteAttributeData.CountInfo; | ||
} | ||
|
||
return ArrayMarshallingInfoProvider.CreateArrayMarshallingInfo(_compilation, type, elementType, countInfo, elementMarshallingInfo); | ||
} | ||
|
||
if (type.SpecialType == SpecialType.System_String) | ||
{ | ||
return CreateStringMarshallingInfo(type, marshalAsInfo); | ||
} | ||
|
||
return marshalAsInfo; | ||
} | ||
|
||
private MarshallingInfo CreateStringMarshallingInfo( | ||
ITypeSymbol type, | ||
MarshalAsInfo marshalAsInfo) | ||
{ | ||
string? marshallerName = marshalAsInfo.UnmanagedType switch | ||
{ | ||
UnmanagedType.BStr => TypeNames.BStrStringMarshaller, | ||
UnmanagedType.LPStr => TypeNames.AnsiStringMarshaller, | ||
UnmanagedType.LPTStr or UnmanagedType.LPWStr => TypeNames.Utf16StringMarshaller, | ||
MarshalAsInfo.UnmanagedType_LPUTF8Str => TypeNames.Utf8StringMarshaller, | ||
_ => null | ||
}; | ||
|
||
if (marshallerName is null) | ||
{ | ||
return marshalAsInfo; | ||
} | ||
|
||
return StringMarshallingInfoProvider.CreateStringMarshallingInfo(_compilation, type, marshallerName); | ||
} | ||
} | ||
} |