diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index 3c9a9afb9c4199..4b46d49f5813f0 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -208,7 +208,7 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL | __`SYSLIB1089`__ | _`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator._ | | __`SYSLIB1090`__ | Invalid 'GeneratedComInterfaceAttribute' usage | | __`SYSLIB1091`__ | Method is declared in different partial declaration than the 'GeneratedComInterface' attribute. | -| __`SYSLIB1092`__ | 'GenerateComInterfaceAttribute' usage not recommended. See aka.ms/GeneratedComInterfaceUsage for recommended usage. | +| __`SYSLIB1092`__ | Usage of '[LibraryImport|GeneratedComInterface]' does not follow recommendation. See aka.ms/[LibraryImport|GeneratedComInterface]Usage for best practices. | | __`SYSLIB1093`__ | Analysis for COM interface generation has failed | | __`SYSLIB1094`__ | The base COM interface failed to generate source. Code will not be generated for this interface. | | __`SYSLIB1095`__ | Invalid 'GeneratedComClassAttribute' usage | diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/DiagnosticDescriptorProvider.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/DiagnosticDescriptorProvider.cs index c676f27cb9f401..fab2d39182c8b7 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/DiagnosticDescriptorProvider.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/DiagnosticDescriptorProvider.cs @@ -26,6 +26,7 @@ internal sealed class DiagnosticDescriptorProvider : IDiagnosticDescriptorProvid GeneratorDiagnostic.NotSupported { NotSupportedDetails: not null, TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails, GeneratorDiagnostic.UnnecessaryData { TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo, GeneratorDiagnostic.UnnecessaryData { TypePositionInfo.IsManagedReturnPosition: true } => GeneratorDiagnostics.UnnecessaryReturnMarshallingInfo, + GeneratorDiagnostic.NotRecommended => GeneratorDiagnostics.GeneratedComInterfaceUsageDoesNotFollowBestPractices, { IsFatal: false } => null, { TypePositionInfo.IsManagedReturnPosition: true } => GeneratorDiagnostics.ReturnTypeNotSupported, { TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.ParameterTypeNotSupported, diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs index b213e3a9704f29..1e1849592f7ba4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs @@ -485,6 +485,17 @@ public class Ids DiagnosticSeverity.Info, isEnabledByDefault: true); + /// + public static readonly DiagnosticDescriptor GeneratedComInterfaceUsageDoesNotFollowBestPractices = + new DiagnosticDescriptor( + Ids.NotRecommendedGeneratedComInterfaceUsage, + GetResourceString(nameof(SR.ComInterfaceUsageDoesNotFollowBestPracticesTitle)), + GetResourceString(nameof(SR.ComInterfaceUsageDoesNotFollowBestPracticesMessageWithDetails)), + Category, + DiagnosticSeverity.Info, + isEnabledByDefault: true, + helpLinkUri: "aka.ms/GeneratedComInterfaceUsage"); + /// /// Report diagnostic for invalid configuration for string marshalling. /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx index ebf0170e328752..2da298e8a7b0df 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx @@ -875,7 +875,13 @@ [In] and [Out] attributes - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. @@ -889,4 +895,19 @@ This type will be treated as a struct in the native signature, not as a native HRESULT - \ No newline at end of file + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf index aba6380486a3b7..48a9bc03b73a63 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf @@ -147,6 +147,16 @@ Hostování .NET COM s EnableComHosting nepodporuje rozhraní s generatedComInterfaceAttribute + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Vrácená hodnota ve spravované definici se při volání nespravované metody COM převede na parametr out. Pokud má být návratovou hodnotou kód HRESULT vrácený nespravovanou metodou COM, použijte u metody [PreserveSig]. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. Atribut [In] není podporován, pokud není použit také atribut [Out]. Blittable arrays nelze zařadit pouze jako [In]. @@ -467,6 +482,11 @@ Poskytnuté atributy „[In]“ a „[Out]“ u tohoto parametru se na tomto parametru nepodporují. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes atributy [In] a [Out] @@ -702,6 +722,16 @@ Neplatné použití atributu VirtualMethodIndexAttribute + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Typ prvku ReadOnlySpan vrácený GetManagedValuesSource musí být stejný, jako typ prvku vrácený GetManagedValuesDestination. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ Typ {0}určuje, že podporuje zařazování ve směru „Out“, ale neposkytuje metodu ToManaged, která vrací spravovaný typ + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. GeneratedComInterfaceAttribute a GeneratedComClassAttribute vyžadují nebezpečný kód. Projekt se musí aktualizovat na <AllowUnsafeBlocks>true</AllowUnsafeBlocks>. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf index 6b978f9aff5a9f..3135aa3bbe7eaa 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf @@ -147,6 +147,16 @@ Das .NET COM-Hosting mit "EnableComHosting" unterstützt keine Schnittstellen mit "GeneratedComInterfaceAttribute". + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Der Rückgabewert in der verwalteten Definition wird beim Aufrufen der nicht verwalteten COM-Methode in einen out-Parameter konvertiert. Wenn als Rückgabewert der von der nicht verwalteten COM-Methode zurückgegebene HRESULT-Code eingesetzt werden soll, verwenden Sie "[PreserveSig]" für die Methode. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. Das [In]-Attribut wird nur unterstützt, wenn auch das [Out]-Attribut verwendet wird. Blittable-Arrays können nicht nur als "[In]" gemarshallt werden. @@ -467,6 +482,11 @@ Die angegebenen Attribute \"[In]\" und \"[Out]\" für diesen Parameter werden für diesen Parameter nicht unterstützt. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In]- und [Out]-Attribute @@ -702,6 +722,16 @@ Ungültige Verwendung von "VirtualMethodIndexAttribute" + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Der von \"GetManagedValuesSource\" zurückgegebene Elementtyp \"ReadOnlySpan\" muss mit dem Elementtyp identisch sein, der von \"GetManagedValuesDestination\" zurückgegeben wird. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ Der Typ \"{0}\" gibt an, dass das Marshalling in der Out-Richtung unterstützt wird. Er stellt jedoch keine ToManaged-Methode bereit, die den verwalteten Typ zurückgibt. + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' und 'GeneratedComClassAttribute' erfordern unsicheren Code. Das Projekt muss mit '<AllowUnsafeBlocks>wahr</AllowUnsafeBlocks>' aktualisiert werden. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf index 077827dbf7ef9b..f0e4701f345ccf 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf @@ -147,6 +147,16 @@ El hospedaje COM de .NET con “EnableComHosting” no admite interfaces con “GeneratedComInterfaceAttribute” + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. El valor devuelto en la definición administrada se convertirá en un parámetro “out” al llamar al método COM no administrado. Si el valor devuelto debe ser el código HRESULT devuelto por el método COM no administrado, use “[PreserveSig]” en el método. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. El atributo '[In]' no se admite a menos que también se use el atributo '[Out]'. Las matrices que se pueden transferir en bloque de bits no se pueden serializar solo como '[In]'. @@ -467,6 +482,11 @@ En este parámetro, los atributos “[In]” y “[Out]” proporcionados no se admiten. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Atributos [In] y [Out] @@ -702,6 +722,16 @@ Uso de ”VirtualMethodIndexAttribute” no válido + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. El tipo de elemento del “ReadOnlySpan” devuelto por “GetManagedValuesSource” debe ser el mismo que el tipo de elemento devuelto por “GetManagedValuesDestination”. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ El tipo “{0}” especifica que admite la serialización en la dirección “Out”, pero no proporciona un método “ToManaged” que devuelva el tipo administrado + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. "GeneratedComInterfaceAttribute" y "GeneratedComClassAttribute" requieren código no seguro. El proyecto debe actualizarse con "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>". diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf index 7b06fbb9966ce1..228abb0f43b9c8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf @@ -147,6 +147,16 @@ L'hébergement .NET COM avec 'EnableComHosting' ne prend pas en charge les interfaces avec 'GeneratedComInterfaceAttribute' + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. La valeur de retour dans la définition managée est convertie en paramètre 'out' lors de l’appel de la méthode COM non managée. Si la valeur de retour doit être le code HRESULT retourné par la méthode COM non managée, utilisez '[PreserveSig]' sur la méthode. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. L’attribut '[In]' n’est pas pris en charge, sauf si l’attribut '[Out]' est également utilisé. Les tableaux blittables ne peuvent pas être marshalés en tant que « [In] » uniquement. @@ -467,6 +482,11 @@ Les attributs « [In] » et « [Out] » fournis sur ce paramètre ne sont pas pris en charge sur ce paramètre. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Attributs [In] et [Out] @@ -702,6 +722,16 @@ Utilisation de « VirtualMethodIndexAttribute » non valide + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Le type d’élément de « ReadOnlySpan » retourné par « GetManagedValuesSource » doit être identique au type d’élément retourné par « GetManagedValuesDestination ». @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - L’attribut '[Out]' est uniquement pris en charge sur les paramètres de tableau. Envisagez d’utiliser des mots clés 'out' ou 'ref' pour rendre le paramètre mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + L’attribut '[Out]' est uniquement pris en charge sur les paramètres de tableau. Envisagez d’utiliser des mots clés 'out' ou 'ref' pour rendre le paramètre mutable. @@ -917,6 +947,11 @@ Le type « {0} » spécifie qu’il prend en charge le marshaling dans la direction « Out », mais il ne fournit pas de méthode « ToManaged » qui retourne le type managé + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. « GeneratedComInterfaceAttribute » et « GeneratedComClassAttribute » nécessitent du code non sécurisé. Le projet doit être mis à jour avec « <AllowUnsafeBlocks>true</AllowUnsafeBlocks> ». diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf index ee4ead36b3e114..58c83094b063bc 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf @@ -147,6 +147,16 @@ L'hosting COM .NET con 'EnableComHosting' non supporta le interfacce con 'GeneratedComInterfaceAttribute'. + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Il valore restituito nella definizione gestita verrà convertito in un parametro 'out' quando si chiama il metodo COM non gestito. Se il valore restituito deve essere il codice HRESULT restituito dal metodo COM non gestito, utilizzare '[PreserveSig]' sul metodo. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. L'attributo '[In]' non è supportato a meno che non venga usato anche l'attributo '[Out]'. Le matrici copiabili da BLT non possono essere sottoposte a marshalling solo come '[In]'. @@ -467,6 +482,11 @@ Gli attributi '[In]' e '[Out]' specificati per questo parametro non sono supportati in questo parametro. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Attributi [In] e [Out] @@ -702,6 +722,16 @@ Utilizzo di 'VirtualMethodIndexAttribute' non valido + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Il tipo di elemento di 'ReadOnlySpan' restituito da 'GetManagedValuesSource' deve essere uguale al tipo di elemento restituito da 'GetManagedValuesDestination'. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - L'attributo '[Out]' è supportato solo nei parametri di matrice. Provare a usare le parole chiave 'out' o 'ref' per rendere modificabile il parametro. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + L'attributo '[Out]' è supportato solo nei parametri di matrice. Provare a usare le parole chiave 'out' o 'ref' per rendere modificabile il parametro. @@ -917,6 +947,11 @@ Il tipo '{0}' specifica che supporta il marshalling nella direzione 'Out', ma non fornisce un metodo 'ToManaged' che restituisce il tipo gestito + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. GeneratedComInterfaceAttribute e 'GeneratedComClassAttribute' richiedono codice non gestito. Il progetto deve essere aggiornato con '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf index 9c12755cb80b44..331eb28eaa414d 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf @@ -147,6 +147,16 @@ 'EnableComHosting' を使用した .NET COM ホスティングでは、'GeneratedComInterfaceAttribute' のインターフェイスはサポートされていません + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. マネージド定義の戻り値は、アンマネージド COM メソッドを呼び出すときに 'out' パラメーターに変換されます。戻り値を、アンマネージド COM メソッドによって返される HRESULT コードにする場合は、メソッドで '[PreserveSig]' を使用してください。 @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. '[In]'属性は、'[Out]'属性も使用しない限りサポートされません。Blittable 配列は、'[In]'としてのみマーシャリングできません。 @@ -467,6 +482,11 @@ このパラメーターに指定された '[In]' 属性と '[Out]' 属性は、このパラメーターではサポートされていません。 + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes 属性の[In]と[Out] @@ -702,6 +722,16 @@ 'VirtualMethodIndexAttribute' の使用法が無効です + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. 'GetManagedValuesSource' によって返される 'ReadOnlySpan' の要素型は、'GetManagedValuesDestination' によって返される要素型と同じである必要があります。 @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ 型 '{0}' は、'Out' 方向のマーシャリングをサポートしますが、マネージド型を返す 'ToManaged' メソッドは指定されません + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' および 'GeneratedComClassAttribute' にはアンセーフ コードが必要です。プロジェクトは '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>' で更新する必要があります。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf index 53b72d47f60fa3..aedf84c829c061 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf @@ -147,6 +147,16 @@ 'EnableComHosting'을 사용한 .NET COM 호스팅은 'GeneratedComInterfaceAttribute'를 사용한 인터페이스를 지원하지 않습니다. + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. 관리 정의의 반환 값은 관리되지 않는 COM 메서드를 호출할 때 'out' 매개 변수로 변환됩니다. 반환 값이 관리되지 않는 COM 메서드에서 반환된 HRESULT 코드인 경우 메서드에서 '[PreserveSig]'를 사용하세요. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. '[Out]' 특성도 사용되지 않는 한 '[In]' 특성은 지원되지 않습니다. Blittable 배열은 '[In]'으로만 마샬링할 수 없습니다. @@ -467,6 +482,11 @@ 이 매개 변수에 제공된 '[In]' 및 '[Out]' 특성은 이 매개 변수에서 지원되지 않습니다. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In] 및 [Out] 속성 @@ -702,6 +722,16 @@ 잘못된 'VirtualMethodIndexAttribute' 사용 + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. 'GetManagedValuesSource'에서 반환된 'ReadOnlySpan'의 요소 형식은 'GetManagedValuesDestination'에서 반환된 요소 형식과 동일해야 합니다. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ 형식 '{0}'은(는) 'Out' 방향으로 마샬링을 지원하도록 지정하지만 관리 형식을 반환하는 'ToManaged' 메서드를 제공하지 않습니다. + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' 및 'GeneratedComClassAttribute'에는 안전하지 않은 코드가 필요합니다. 프로젝트를 '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'로 업데이트해야 합니다. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf index fb6cf9f172c21b..f051d95f3b9c9e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf @@ -147,6 +147,16 @@ Hosting modelu COM platformy .NET z elementem „EnableComHosting” nie obsługuje interfejsów z atrybutem „GeneratedComInterfaceAttribute” + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Wartość zwracana w definicji zarządzanej zostanie przekonwertowana na parametr „out” podczas wywoływania niezarządzanej metody COM. Jeśli wartość zwracana ma być kodem HRESULT zwracanym przez niezarządzaną metodę COM, należy użyć „[PreserveSig]” w metodzie. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. Atrybut „[In]” nie jest obsługiwany, chyba że używany jest również atrybut „[Out]”. Tablice kopiowalne nie mogą być kierowane tylko jako „[In]”. @@ -467,6 +482,11 @@ Podane atrybuty „[In]” i „[Out]” w tym parametrze nie są obsługiwane w tym parametrze. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Atrybuty [In] i [Out] @@ -702,6 +722,16 @@ Nieprawidłowe użycie atrybutu „VirtualMethodIndexAttribute” + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Typ elementu „ReadOnlySpan” zwracany przez element „GetManagedValuesSource” musi być taki sam jak typ elementu zwracany przez element „GetManagedValuesDestination”. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - Atrybut „[Out]” jest obsługiwany tylko w przypadku parametrów tablicy. Rozważ użycie słów kluczowych „out” lub „ref”, aby umożliwić modyfikowanie parametru. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + Atrybut „[Out]” jest obsługiwany tylko w przypadku parametrów tablicy. Rozważ użycie słów kluczowych „out” lub „ref”, aby umożliwić modyfikowanie parametru. @@ -917,6 +947,11 @@ Typ „{0}” określa, że obsługuje skierowanie w kierunku „Out”, ale nie zapewnia metody „ToManaged”, która zwraca typ zarządzany + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. Atrybut „GeneratedComInterfaceAttribute” i „GeneratedComClassAttribute” wymagają niebezpiecznego kodu. Projekt musi zostać zaktualizowany za pomocą polecenia „<AllowUnsafeBlocks>true</AllowUnsafeBlocks>”. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf index 8d2e606d2d0307..c1bc60315bc05c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf @@ -147,6 +147,16 @@ A hospedagem .NET COM com 'EnableComHosting' não dá suporte a interfaces com 'GeneratedComInterfaceAttribute' + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. O valor de retorno na definição gerenciada será convertido em um parâmetro 'out' ao chamar o método COM não gerenciado. Se o valor de retorno for o código HRESULT retornado pelo método COM não gerenciado, use '[PreserveSig]' no método. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. O atributo '[In]' não é suportado, a menos que o atributo '[Out]' também seja usado. Matrizes Blittable não podem ser empacotadas apenas como '[In]'. @@ -467,6 +482,11 @@ Os atributos '[In]' e '[Out]' neste parâmetro não têm suporte neste parâmetro. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Atributos [In] e [Out] @@ -702,6 +722,16 @@ Uso de 'VirtualMethodIndexAttribute' inválido + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. O tipo de elemento de 'ReadOnlySpan' retornado por 'GetManagedValuesSource' deve ser igual ao tipo de elemento retornado por 'GetManagedValuesDestination'. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ O tipo '{0}' especifica que ele dá suporte a marshalling na direção 'Out', mas não fornece um método 'ToManaged' que retorna o tipo gerenciado + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. "GeneratedComInterfaceAttribute" e "GeneratedComClassAttribute" exigem código não seguro. O projeto deve ser atualizado com "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>". diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf index fca13d2b25e7f6..891ef9d077eb61 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf @@ -147,6 +147,16 @@ Размещение .NET COM с "EnableComHosting" не поддерживает интерфейсы с "GeneratedComInterfaceAttribute" + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Возвращаемое значение в управляемом определении будет преобразовано в параметр "out" при вызове неуправляемого метода COM. Если возвращаемое значение должно быть кодом HRESULT, возвращаемым неуправляемым COM-методом, используйте "[PreserveSig]" в методе. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. Атрибут "[In]" не поддерживается, если также не используется атрибут "[Out]". Преобразуемые массивы нельзя сортировать только как "[In]". @@ -467,6 +482,11 @@ Указанные атрибуты \"[In]\" и \"[Out]\" для этого параметра не поддерживаются. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Атрибуты [In] и [Out] @@ -702,6 +722,16 @@ Недопустимое использование VirtualMethodIndexAttribute + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Тип элемента \"ReadOnlySpan\", возвращенный методом \"GetManagedValuesSource\", должен совпадать с типом элемента, возвращаемым методом \"GetManagedValuesDestination\". @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - Атрибут "[Out]" поддерживается только для параметров массива. Рассмотрите возможность использования ключевых слов "out" или "ref", чтобы сделать параметр изменяемым. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + Атрибут "[Out]" поддерживается только для параметров массива. Рассмотрите возможность использования ключевых слов "out" или "ref", чтобы сделать параметр изменяемым. @@ -917,6 +947,11 @@ Тип \"{0}\" указывает, что поддерживает маршализацию в направлении \"наружу\", но не предоставляет метод \"ToManaged\", который возвращает управляемый тип + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. Для "GeneratedComInterfaceAttribute" и "GeneratedComClassAttribute" требуется небезопасный код. Проект необходимо обновить с использованием значения "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>". diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf index 44d2a4a4cbadd3..6748b1305030b9 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf @@ -147,6 +147,16 @@ 'EnableComHosting' ile barındırma .NET COM, 'GeneratedComInterfaceAttribute' ile arabirimleri desteklemez + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Yönetilen tanımdaki dönüş değeri, yönetilmeyen COM yöntemi çağrılırken 'out' parametresine dönüştürülür. Dönüş değerinin yönetilmeyen COM yöntemi tarafından döndürülen HRESULT kodu olması amaçlanmışsa, yöntemde '[PreserveSig]' kullanın. @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. '[Out]' özniteliği de kullanılmadığı sürece '[In]' özniteliği desteklenmez. Blittable dizileri yalnızca '[In]' olarak hazırlanamaz. @@ -467,6 +482,11 @@ Bu parametrede sağlanan '[In]' ve '[Out]' öznitelikleri bu parametrede desteklenmiyor. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In] ve [Out] öznitelikleri @@ -702,6 +722,16 @@ Geçersiz 'VirtualMethodIndexAttribute' kullanımı + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. 'GetManagedValuesSource' tarafından döndürülen 'ReadOnlySpan' öğe türü, 'GetManagedValuesDestination' tarafından döndürülen öğe türüyle aynı olmalıdır. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - '[Out]' özniteliği yalnızca dizi parametrelerinde desteklenir. Parametreyi değiştirilebilir yapmak için 'out' veya 'ref' anahtar sözcükleri kullanmayı düşünün. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + '[Out]' özniteliği yalnızca dizi parametrelerinde desteklenir. Parametreyi değiştirilebilir yapmak için 'out' veya 'ref' anahtar sözcükleri kullanmayı düşünün. @@ -917,6 +947,11 @@ '{0}' türü, 'Out' yönünde sıralamayı desteklediğini belirtiyor, ancak yönetilen türü döndüren bir 'ToManaged' metodu sağlamıyor + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' ve 'GeneratedComClassAttribute' güvenli olmayan kod gerektiriyor. Projenin '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>' ile güncelleştirilmiş olması gerekiyor. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf index e6fbf9115aec2d..de0d085a227a7e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf @@ -147,6 +147,16 @@ 具有“EnableComHosting”的 .NET COM 托管不支持具有“GeneratedComInterfaceAttribute”的接口 + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. 调用非托管 COM 方法时,托管定义中的返回值将转换为 "out" 参数。如果返回值是非托管 COM 方法返回的 HRESULT 代码,请对方法使用 "[PreserveSig]"。 @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. 不支持“[In]”属性,除非也使用“[Out]”属性。不能仅将 Blittable 数组封送为“[In]”。 @@ -467,6 +482,11 @@ 此参数上提供的 “[In]” 和 “[Out]” 属性在此参数上不受支持。 + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In] 和 [Out] 属性 @@ -702,6 +722,16 @@ “VirtualMethodIndexAttribute” 使用情况无效 + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. “GetManagedValuesSource” 返回的 “ReadOnlySpan” 的元素类型必须与 “GetManagedValuesDestination” 返回的元素类型相同。 @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ 类型“{0}”指定它支持按 “Out” 方向进行封送,但不提供返回托管类型的 “ToManaged” 方法 + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. “GeneratedComInterfaceAttribute”和“GeneratedComClassAttribute”需要不安全代码。必须将项目更新为“<AllowUnsafeBlocks>true</AllowUnsafeBlocks>”。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf index 528339678cefdb..408df3131a3be5 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf @@ -147,6 +147,16 @@ 以 'EnableComHosting' 裝載的 .NET COM 不支援具有 'GeneratedComInterfaceAttribute' 的介面 + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. 呼叫未受控 COM 方法時,受控定義中的傳回值將轉換為 'out' 參數。如果傳回值預期是未受控 COM 方法傳回的 HRESULT 代碼,請在方法上使用 '[PreserveSig]'。 @@ -447,6 +457,11 @@ This type will be treated as a struct in the native signature, not as a native HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. 除非也使用 '[Out]' 屬性,否則不支援 '[In]' 屬性。無法只將 Blittable 陣列整理為 '[In]'。 @@ -467,6 +482,11 @@ 此參數不支援在此參數上提供的 '[In]' 和 '[Out]' 屬性。 + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In] 與 [Out] 屬性 @@ -702,6 +722,16 @@ 'VirtualMethodIndexAttribute' 使用方式無效 + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. 'GetManagedValuesSource' 傳回的 'ReadOnlySpan' 元素類型必須與 'GetManagedValuesDestination' 傳回的元素類型相同。 @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - 只有陣列參數才支援 '[Out]' 屬性。請考慮使用 'out' 或 'ref' 關鍵字將參數設為可變。 + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + 只有陣列參數才支援 '[Out]' 屬性。請考慮使用 'out' 或 'ref' 關鍵字將參數設為可變。 @@ -917,6 +947,11 @@ 類型 '{0}' 指定它支援以 'Out' 方向排列,但未提供傳回受管理類型的 'ToManaged' 方法 + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' 和 'GeneratedComClassAttribute' 需要不安全的程式碼。專案必須以 '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>' 更新。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DiagnosticDescriptorProvider.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DiagnosticDescriptorProvider.cs index 2bef64490f9a4e..eb9a0237307bc3 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DiagnosticDescriptorProvider.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DiagnosticDescriptorProvider.cs @@ -24,6 +24,7 @@ internal sealed class DiagnosticDescriptorProvider : IDiagnosticDescriptorProvid GeneratorDiagnostic.NotSupported { NotSupportedDetails: not null, TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails, GeneratorDiagnostic.UnnecessaryData { TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo, GeneratorDiagnostic.UnnecessaryData { TypePositionInfo.IsManagedReturnPosition: true } => GeneratorDiagnostics.UnnecessaryReturnMarshallingInfo, + GeneratorDiagnostic.NotRecommended => GeneratorDiagnostics.LibraryImportUsageDoesNotFollowBestPractices, { IsFatal: false } => null, { TypePositionInfo.IsManagedReturnPosition: true } => GeneratorDiagnostics.ReturnTypeNotSupported, { TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.ParameterTypeNotSupported, diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs index 2af2abadcdd607..f5fd78d48e587c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs @@ -254,6 +254,16 @@ public class Ids DiagnosticSeverity.Warning, isEnabledByDefault: true); + /// + public static readonly DiagnosticDescriptor LibraryImportUsageDoesNotFollowBestPractices = + new DiagnosticDescriptor( + Ids.NotRecommendedGeneratedComInterfaceUsage, + GetResourceString(nameof(SR.LibraryImportUsageDoesNotFollowBestPracticesTitle)), + GetResourceString(nameof(SR.LibraryImportUsageDoesNotFollowBestPracticesMessageWithDetails)), + Category, + DiagnosticSeverity.Info, + isEnabledByDefault: true); + /// /// Report diagnostic for invalid configuration for string marshalling. /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalValuesProviderExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalValuesProviderExtensions.cs index 123d649c913cd5..5455510ac356c0 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalValuesProviderExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalValuesProviderExtensions.cs @@ -47,7 +47,7 @@ public static IncrementalValuesProvider SelectNormalized(this Incr return provider.Select((node, ct) => node.NormalizeWhitespace()); } - public static (IncrementalValuesProvider, IncrementalValuesProvider) Split(this IncrementalValuesProvider<(T, T2)> provider) + public static (IncrementalValuesProvider, IncrementalValuesProvider) Split(this IncrementalValuesProvider<(T, T2)> provider) { return (provider.Select(static (data, ct) => data.Item1), provider.Select(static (data, ct) => data.Item2)); } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs index 73b8cd8eb901a9..69180eca11c190 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs @@ -431,17 +431,10 @@ private ResolvedGenerator CreateNativeCollectionMarshaller( { byValueMarshalKindSupport = ByValueMarshalKindSupportDescriptor.Default; } - else if (!elementIsBlittable || ElementTypeIsSometimesNonBlittable(elementInfo)) - { - // If the type is not blittable or is sometimes not blittable, we will generate different code when the attributes are provided. - byValueMarshalKindSupport = ByValueMarshalKindSupportDescriptor.ArrayParameter; - } else { - // If the type is always blittable, we'll generate the same code regardless of the attributes, - // but we'll allow them to make it easier to transition to source-generated code and allow users to be clear about expectations - // for values in pre-allocated buffers. - byValueMarshalKindSupport = ByValueMarshalKindSupportDescriptor.PinnedParameter; + // If we have an array, we will use the Array [In, Out] support descriptor + byValueMarshalKindSupport = ByValueMarshalKindSupportDescriptor.ArrayParameter; } // Elements in the collection must be blittable to use the pinnable marshaller. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs index 5cc2a8f9a9b261..dd7a40fb8c90e2 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs @@ -27,7 +27,7 @@ public ResolvedGenerator Create(TypePositionInfo info, StubCodeContext context) private static ResolvedGenerator ValidateByValueMarshalKind(TypePositionInfo info, StubCodeContext context, ResolvedGenerator generator) { - if (generator.Generator is Forwarder || info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.Default) + if (generator.Generator is Forwarder) { // Forwarder allows everything since it just forwards to a P/Invoke. // The Default marshal kind is always valid. @@ -41,6 +41,7 @@ private static ResolvedGenerator ValidateByValueMarshalKind(TypePositionInfo inf ByValueMarshalKindSupport.Supported => generator, ByValueMarshalKindSupport.NotSupported => ResolvedGenerator.ResolvedWithDiagnostics(s_forwarder, generator.Diagnostics.Add(diagnostic!)), ByValueMarshalKindSupport.Unnecessary => generator with { Diagnostics = generator.Diagnostics.Add(diagnostic!) }, + ByValueMarshalKindSupport.NotRecommended => generator with { Diagnostics = generator.Diagnostics.Add(diagnostic!) }, _ => throw new UnreachableException() }; } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueMarshalKindSupportDescriptor.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueMarshalKindSupportDescriptor.cs index 1f859d34ff919b..7754e177d66063 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueMarshalKindSupportDescriptor.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueMarshalKindSupportDescriptor.cs @@ -3,127 +3,105 @@ using System; using System.Collections.Immutable; +using System.Diagnostics; namespace Microsoft.Interop { + public record struct ByValueMarshalKindSupportInfo(ByValueMarshalKindSupport Support, string? details) + { + public ByValueMarshalKindSupport GetSupport(TypePositionInfo info, StubCodeContext context, out GeneratorDiagnostic? diagnostic) + { + diagnostic = Support switch + { + ByValueMarshalKindSupport.Supported => null, + ByValueMarshalKindSupport.NotRecommended => + new GeneratorDiagnostic.NotRecommended(info, context) + { + Details = details + }, + ByValueMarshalKindSupport.Unnecessary => + new GeneratorDiagnostic.UnnecessaryData( + info, + context, + ImmutableArray.Create(info.ByValueMarshalAttributeLocations.OutLocation)) + { + UnnecessaryDataName = SR.InOutAttributes, + UnnecessaryDataDetails = details + }, + ByValueMarshalKindSupport.NotSupported => + new GeneratorDiagnostic.NotSupported(info, context) + { + NotSupportedDetails = details + }, + _ => throw new UnreachableException() + }; + return Support; + } + } + /// /// Provides an implementation of through /// public record ByValueMarshalKindSupportDescriptor( - ByValueMarshalKindSupport InSupport, string? InSupportDetails, - ByValueMarshalKindSupport OutSupport, string? OutSupportDetails, - ByValueMarshalKindSupport InOutSupport, string? InOutSupportDetails) + ByValueMarshalKindSupportInfo DefaultSupport, + ByValueMarshalKindSupportInfo InSupport, + ByValueMarshalKindSupportInfo OutSupport, + ByValueMarshalKindSupportInfo InOutSupport) { /// /// A default for by value parameters. [In] is allowed, but unnecessary. Out is not allowed. /// public static readonly ByValueMarshalKindSupportDescriptor Default = new ByValueMarshalKindSupportDescriptor( - InSupport: ByValueMarshalKindSupport.Unnecessary, InSupportDetails: SR.InAttributeOnlyIsDefault, - OutSupport: ByValueMarshalKindSupport.NotSupported, OutSupportDetails: SR.OutAttributeNotSupportedOnByValueParameters, - InOutSupport: ByValueMarshalKindSupport.NotSupported, InOutSupportDetails: SR.OutAttributeNotSupportedOnByValueParameters); + DefaultSupport: new(ByValueMarshalKindSupport.Supported, null), + InSupport: new(ByValueMarshalKindSupport.NotSupported, SR.InAttributeNotSupportedOnByValueParameters), + OutSupport: new(ByValueMarshalKindSupport.NotSupported, SR.OutAttributeNotSupportedOnByValueParameters), + InOutSupport: new(ByValueMarshalKindSupport.NotSupported, SR.InOutAttributeNotSupportedOnByValueParameters)); /// - /// A default for by value array parameters. [In] is allowed, but unnecessary. Out is allowed. + /// A default for by value array parameters. Default is allowed, but Not Recommended. [In], [Out], and [In, Out] are allowed /// public static readonly ByValueMarshalKindSupportDescriptor ArrayParameter = new ByValueMarshalKindSupportDescriptor( - InSupport: ByValueMarshalKindSupport.Unnecessary, InSupportDetails: SR.InAttributeOnlyIsDefault, - OutSupport: ByValueMarshalKindSupport.Supported, OutSupportDetails: null, - InOutSupport: ByValueMarshalKindSupport.Supported, InOutSupportDetails: null); - - /// - /// A default for pinned parameters. [In] is allowed, but unnecessary. Out is allowed. - /// - public static readonly ByValueMarshalKindSupportDescriptor PinnedParameter = new ByValueMarshalKindSupportDescriptor( - InSupport: ByValueMarshalKindSupport.Unnecessary, InSupportDetails: SR.InAttributeOnlyIsDefault, - OutSupport: ByValueMarshalKindSupport.Supported, OutSupportDetails: null, - InOutSupport: ByValueMarshalKindSupport.Supported, InOutSupportDetails: null); + DefaultSupport: new(ByValueMarshalKindSupport.NotRecommended, SR.PreferExplicitInOutAttributesOnArrays), + InSupport: new(ByValueMarshalKindSupport.Supported, null), + OutSupport: new(ByValueMarshalKindSupport.Supported, null), + InOutSupport: new(ByValueMarshalKindSupport.Supported, null)); /// /// Returns the support for the ByValueContentsMarshalKind, and if it is not , diagnostic is not null /// public ByValueMarshalKindSupport GetSupport(ByValueContentsMarshalKind marshalKind, TypePositionInfo info, StubCodeContext context, out GeneratorDiagnostic? diagnostic) { - if (info.IsByRef && marshalKind != ByValueContentsMarshalKind.Default) + if (info.IsByRef) { - diagnostic = new GeneratorDiagnostic.NotSupported(info, context) + // ByRef with ByValue attributes is not allowed + if (marshalKind != ByValueContentsMarshalKind.Default) { - NotSupportedDetails = SR.InOutAttributeByRefNotSupported - }; - return ByValueMarshalKindSupport.NotSupported; - } - switch (marshalKind) - { - case ByValueContentsMarshalKind.Default: - diagnostic = null; - return ByValueMarshalKindSupport.Supported; - case ByValueContentsMarshalKind.Out: - diagnostic = OutSupport switch + diagnostic = new GeneratorDiagnostic.NotSupported(info, context) { - ByValueMarshalKindSupport.Supported => null, - ByValueMarshalKindSupport.Unnecessary - => new GeneratorDiagnostic.UnnecessaryData( - info, - context, - ImmutableArray.Create(info.ByValueMarshalAttributeLocations.OutLocation)) - { - UnnecessaryDataName = SR.InOutAttributes, - UnnecessaryDataDetails = OutSupportDetails - }, - ByValueMarshalKindSupport.NotSupported - => new GeneratorDiagnostic.NotSupported( - info, - context) - { NotSupportedDetails = OutSupportDetails }, - _ => throw new UnreachableException($"Unexpected {nameof(ByValueMarshalKindSupport)} Variant: {InOutSupport}") + NotSupportedDetails = SR.InOutAttributeByRefNotSupported }; - return OutSupport; - case ByValueContentsMarshalKind.In: - diagnostic = InSupport switch - { - ByValueMarshalKindSupport.Supported => null, - ByValueMarshalKindSupport.Unnecessary - => new GeneratorDiagnostic.UnnecessaryData( - info, - context, - ImmutableArray.Create(info.ByValueMarshalAttributeLocations.InLocation)) - { - UnnecessaryDataName = SR.InOutAttributes, - UnnecessaryDataDetails = InSupportDetails - }, - ByValueMarshalKindSupport.NotSupported - => new GeneratorDiagnostic.NotSupported( - info, - context) - { NotSupportedDetails = InSupportDetails }, - _ => throw new UnreachableException($"Unexpected {nameof(ByValueMarshalKindSupport)} Variant: {InOutSupport}") - }; - return InSupport; - case ByValueContentsMarshalKind.InOut: - diagnostic = InOutSupport switch - { - ByValueMarshalKindSupport.Supported => null, - ByValueMarshalKindSupport.Unnecessary - => new GeneratorDiagnostic.UnnecessaryData( - info, - context, - ImmutableArray.Create( - info.ByValueMarshalAttributeLocations.InLocation, - info.ByValueMarshalAttributeLocations.OutLocation)) - { - UnnecessaryDataName = SR.InOutAttributes, - UnnecessaryDataDetails = InOutSupportDetails - }, - ByValueMarshalKindSupport.NotSupported - => new GeneratorDiagnostic.NotSupported( - info, - context) - { NotSupportedDetails = InOutSupportDetails }, - _ => throw new UnreachableException($"Unexpected {nameof(ByValueMarshalKindSupport)} Variant: {InOutSupport}") - }; - return InOutSupport; - default: - throw new UnreachableException($"Unexpected {nameof(ByValueContentsMarshalKind)} variant: {marshalKind}"); + return ByValueMarshalKindSupport.NotSupported; + } + // ByRef with no ByValue attributes is supported + diagnostic = null; + return ByValueMarshalKindSupport.Supported; + } + // Return can never have In or Out attributes, so can assume valid ByValue attributes + if (info.ManagedIndex < 0) + { + Debug.Assert(marshalKind is ByValueContentsMarshalKind.Default); + diagnostic = null; + return ByValueMarshalKindSupport.Supported; } + + return marshalKind switch + { + ByValueContentsMarshalKind.Default => DefaultSupport.GetSupport(info, context, out diagnostic), + ByValueContentsMarshalKind.In => InSupport.GetSupport(info, context, out diagnostic), + ByValueContentsMarshalKind.Out => OutSupport.GetSupport(info, context, out diagnostic), + ByValueContentsMarshalKind.InOut => InOutSupport.GetSupport(info, context, out diagnostic), + _ => throw new UnreachableException() + }; } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/GeneratorDiagnostic.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/GeneratorDiagnostic.cs index 22444e79824c9b..02820335ec176e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/GeneratorDiagnostic.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/GeneratorDiagnostic.cs @@ -62,5 +62,18 @@ public override DiagnosticInfo ToDiagnosticInfo(DiagnosticDescriptor descriptor, UnnecessaryDataDetails ?? ""); } } + + public sealed record NotRecommended(TypePositionInfo TypePositionInfo, StubCodeContext StubCodeContext) : GeneratorDiagnostic(TypePositionInfo, StubCodeContext, isFatal: false) + { + public string? Details { get; init; } + + public override DiagnosticInfo ToDiagnosticInfo(DiagnosticDescriptor descriptor, Location location, string elementName) + { + return DiagnosticInfo.Create( + descriptor, + location, + Details); + } + } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs index f5e8aacdaa3c15..598ba380028946 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs @@ -83,6 +83,10 @@ public enum ByValueMarshalKindSupport /// The provided is supported but does not change behavior from the default in this scenario. /// Unnecessary, + /// + /// The provided is supported but does not follow best practices. + /// + NotRecommended, } /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StaticPinnableManagedValueMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StaticPinnableManagedValueMarshaller.cs index 45ef61f85dbc58..039d78ed350068 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StaticPinnableManagedValueMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StaticPinnableManagedValueMarshaller.cs @@ -105,7 +105,7 @@ private IEnumerable GeneratePinningPath(TypePositionInfo info, public ByValueMarshalKindSupport SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, TypePositionInfo info, StubCodeContext context, out GeneratorDiagnostic? diagnostic) { - return ByValueMarshalKindSupportDescriptor.PinnedParameter.GetSupport(marshalKind, info, context, out diagnostic); + return _innerMarshallingGenerator.SupportsByValueMarshalKind(marshalKind, info, context, out diagnostic); } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs new file mode 100644 index 00000000000000..fdd2d33d6e7d27 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs @@ -0,0 +1,301 @@ +// 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.Diagnostics; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.Interop; +using Xunit; +using static Microsoft.Interop.UnitTests.TestUtils; +using StringMarshalling = System.Runtime.InteropServices.StringMarshalling; +using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; + +namespace ComInterfaceGenerator.Unit.Tests +{ + public class ByValueContentsMarshalling + { + private static IComInterfaceAttributeProvider GetAttributeProvider(GeneratorKind generator) + => generator switch + { + GeneratorKind.VTableIndexStubGenerator => new VirtualMethodIndexAttributeProvider(), + GeneratorKind.ComInterfaceGeneratorManagedObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ManagedObjectWrapper), + GeneratorKind.ComInterfaceGeneratorComObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ComObjectWrapper), + GeneratorKind.ComInterfaceGenerator => new GeneratedComInterfaceAttributeProvider(), + _ => throw new UnreachableException(), + }; + + public static IEnumerable ByValueMarshalAttributeOnValueTypes() + { + var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); + const string In = "[{|#1:InAttribute|}]"; + const string Out = "[{|#2:OutAttribute|}]"; + const string paramName = "p"; + const string MarshalAsU4 = "[MarshalAs(UnmanagedType.U4)]"; + const string MarshalAsU2 = "[MarshalAs(UnmanagedType.U2)]"; + + string p = $$"""{|#0:{{paramName}}|}"""; + var diagnostic = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails); + var outAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); + var inAttributeIsNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InAttributeNotSupportedOnByValueParameters, paramName); + var inOutAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InOutAttributeNotSupportedOnByValueParameters, paramName); + + DiagnosticResult[] InIsNotSupported = [inAttributeIsNotSupported]; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In, "int", p), InIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In, "byte", p), InIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + MarshalAsU4, "bool", p), InIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + MarshalAsU2, "char", p), InIsNotSupported }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In, "string", p, (StringMarshalling.Utf8, null)), InIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In, "IntClass", p) + CodeSnippets.IntClassAndMarshaller, InIsNotSupported }; + + DiagnosticResult[] OutIsNotSupported = [outAttributeNotSupported]; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out, "int", p), OutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out, "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, OutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + MarshalAsU4, "bool", p), OutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + MarshalAsU2, "char", p), OutIsNotSupported }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out, "string", p, (StringMarshalling.Utf8, null)), OutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out, "IntClass", p) + CodeSnippets.IntClassAndMarshaller, OutIsNotSupported }; + + DiagnosticResult[] InOutIsNotSupported = [inOutAttributeNotSupported]; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out, "int", p), InOutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out, "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, InOutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + MarshalAsU4, "bool", p), InOutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + MarshalAsU2, "char", p), InOutIsNotSupported }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out, "string", p, (StringMarshalling.Utf8, null)), InOutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out, "IntClass", p) + CodeSnippets.IntClassAndMarshaller, InOutIsNotSupported }; + + // Any ref keyword is okay for non-collection types + DiagnosticResult[] None = []; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("out", "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("out", "byte", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU4 + "out", "bool", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU2 + "out", "char", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("out", "string", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("out", "IntClass", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("in", "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("in", "byte", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU4 + "in", "bool", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU2 + "in", "char", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("in", "string", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("in", "IntClass", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("ref", "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("ref", "byte", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU4 + "ref", "bool", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU2 + "ref", "char", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("ref", "string", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("ref", "IntClass", p) + CodeSnippets.IntClassAndMarshaller, None }; + } + + public static IEnumerable ByValueMarshalAttributeOnPinnedMarshalledTypes() + { + var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); + const string In = "[{|#1:InAttribute|}]"; + const string Out = "[{|#2:OutAttribute|}]"; + const string paramName = "p"; + string p = $$"""{|#0:{{paramName}}|}"""; + const string Count = @"[MarshalUsing(ConstantElementCount = 10)]"; + const string MarshalAsBoolArray = "[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeConst = 10)]"; + const string MarshalUsingIntMarshaller = "[MarshalUsing(typeof(IntMarshaller), ElementIndirectionDepth = 1)]"; + const string MarshalUsingIntStructMarshaller = "[MarshalUsing(typeof(IntStructMarshaller), ElementIndirectionDepth = 1)]"; + const string MarshalUsingIntClassMarshaller = "[MarshalUsing(typeof(IntClassMarshaller), ElementIndirectionDepth = 1)]"; + + // Any explicit [In] or [Out] on an array is preferred and should not warn + DiagnosticResult[] None = []; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count, "int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count, "char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + MarshalAsBoolArray, "bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + MarshalUsingIntMarshaller + Count, "int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count, "string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count, "string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count + MarshalUsingIntStructMarshaller, "IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count + MarshalUsingIntClassMarshaller, "IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count, "int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count, "char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + MarshalAsBoolArray, "bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + MarshalUsingIntMarshaller + Count, "int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count, "string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count, "string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count + MarshalUsingIntStructMarshaller, "IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count + MarshalUsingIntClassMarshaller, "IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count, "int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count, "char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + MarshalAsBoolArray, "bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + MarshalUsingIntMarshaller + Count, "int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count, "string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count, "string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count + MarshalUsingIntStructMarshaller, "IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count + MarshalUsingIntClassMarshaller, "IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + // Array parameters without [In] or [Out] should provide an Info diagnostic + var preferExplicitAttributesDiagnostic = new DiagnosticResult(GeneratorDiagnostics.GeneratedComInterfaceUsageDoesNotFollowBestPractices) + .WithLocation(0) + .WithArguments(SR.PreferExplicitInOutAttributesOnArrays); + DiagnosticResult[] PreferInOutAttributes = [preferExplicitAttributesDiagnostic]; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "int[]", p), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "char[]", p, (StringMarshalling.Utf16, null)), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsBoolArray, "bool[]", p, (StringMarshalling.Utf16, null)), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalUsingIntMarshaller + Count, "int[]", p) + CodeSnippets.IntMarshaller, PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "string[]", p, (StringMarshalling.Utf16, null)), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "string[]", p, (StringMarshalling.Utf8, null)), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntStructMarshaller, "IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntClassMarshaller, "IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, PreferInOutAttributes }; + + // Ref Kinds shouldn't warn + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "in int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "in char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsBoolArray, "in bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalUsingIntMarshaller + Count, "in int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "in string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "in string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntStructMarshaller, "in IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntClassMarshaller, "in IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "out int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "out char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsBoolArray, "out bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalUsingIntMarshaller + Count, "out int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "out string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "out string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntStructMarshaller, "out IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntClassMarshaller, "out IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "ref int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "ref char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsBoolArray, "ref bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalUsingIntMarshaller + Count, "ref int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "ref string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "ref string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntStructMarshaller, "ref IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntClassMarshaller, "ref IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + } + + public static IEnumerable ByValueMarshalAttributeOnCustomCollections() + { + var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); + const string In = "[{|#1:InAttribute|}]"; + const string Out = "[{|#2:OutAttribute|}]"; + const string paramName = "p"; + string p = $$"""{|#0:{{paramName}}|}"""; + const string CollectionMarshaller = "StatelessCollectionAllShapesMarshaller<,>"; + + var diagnostic = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails); + var outAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); + var inAttributeIsNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InAttributeNotSupportedOnByValueParameters, paramName); + var inOutAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InOutAttributeNotSupportedOnByValueParameters, paramName); + + DiagnosticResult[] InIsNotSupported = [inAttributeIsNotSupported]; + DiagnosticResult[] OutIsNotSupported = [outAttributeNotSupported]; + DiagnosticResult[] InOutIsNotSupported = [inOutAttributeNotSupported]; + DiagnosticResult[] None = []; + + yield return new object[] { ID(), Source("", "int"), None }; + yield return new object[] { ID(), Source("", "byte"), None }; + yield return new object[] { ID(), Source(MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, None }; + yield return new object[] { ID(), Source(MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), Source("", "string", (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), Source("", "string", (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), Source(MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), None }; + + // [In] and [Out] are not allowed on custom collections + yield return new object[] { ID(), Source(In, "int"), InIsNotSupported }; + yield return new object[] { ID(), Source(In, "byte"), InIsNotSupported }; + yield return new object[] { ID(), Source(In + MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, InIsNotSupported }; + yield return new object[] { ID(), Source(In + MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, InIsNotSupported }; + yield return new object[] { ID(), Source(In, "string", (StringMarshalling.Utf16, null)), InIsNotSupported }; + yield return new object[] { ID(), Source(In, "string", (StringMarshalling.Utf8, null)), InIsNotSupported }; + yield return new object[] { ID(), Source(In + MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), InIsNotSupported }; + + yield return new object[] { ID(), Source(Out, "int"), OutIsNotSupported }; + yield return new object[] { ID(), Source(Out, "byte"), OutIsNotSupported }; + yield return new object[] { ID(), Source(Out + MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, OutIsNotSupported }; + yield return new object[] { ID(), Source(Out + MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, OutIsNotSupported }; + yield return new object[] { ID(), Source(Out, "string", (StringMarshalling.Utf16, null)), OutIsNotSupported }; + yield return new object[] { ID(), Source(Out, "string", (StringMarshalling.Utf8, null)), OutIsNotSupported }; + yield return new object[] { ID(), Source(Out + MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), OutIsNotSupported }; + + yield return new object[] { ID(), Source(In + Out, "int"), InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out, "byte"), InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out + MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out + MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out, "string", (StringMarshalling.Utf16, null)), InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out, "string", (StringMarshalling.Utf8, null)), InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out + MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), InOutIsNotSupported }; + + // RefKind modifiers are okay + yield return new object[] { ID(), SourceWithRefKind("in", "", "int"), None }; + yield return new object[] { ID(), SourceWithRefKind("in", "", "byte"), None }; + yield return new object[] { ID(), SourceWithRefKind("in", MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("in", MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("in", "", "string", (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("in", "", "string", (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("in", MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), None }; + + yield return new object[] { ID(), SourceWithRefKind("out", "", "int"), None }; + yield return new object[] { ID(), SourceWithRefKind("out", "", "byte"), None }; + yield return new object[] { ID(), SourceWithRefKind("out", MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("out", MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("out", "", "string", (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("out", "", "string", (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("out", MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), None }; + + yield return new object[] { ID(), SourceWithRefKind("ref", "", "int"), None }; + yield return new object[] { ID(), SourceWithRefKind("ref", "", "byte"), None }; + yield return new object[] { ID(), SourceWithRefKind("ref", MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("ref", MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("ref", "", "string", (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("ref", "", "string", (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("ref", MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), None }; + + string Source(string Attributes, string type, (StringMarshalling StringMarshalling, Type? StringMarshallingCustomType)? stringMarshalling = null) + => SourceWithRefKind("", Attributes, type, stringMarshalling); + + string SourceWithRefKind(string refKind, string Attributes, string type, (StringMarshalling StringMarshalling, Type? StringMarshallingCustomType)? stringMarshalling = null) + { + return codeSnippets.ByValueMarshallingOfType(Attributes + MarshalCollection(), CodeSnippets.GetCustomCollectionType(type), p, stringMarshalling) + CodeSnippets.CustomCollectionAndMarshaller; + } + static string MarshalUsing(string marshaller = CollectionMarshaller, int depth = 0) + => $"[MarshalUsing(typeof({marshaller}), ElementIndirectionDepth = {depth})]"; + static string MarshalCollection(int depth = 0) + => $"[MarshalUsing(typeof({CollectionMarshaller}), ElementIndirectionDepth = {depth}, ConstantElementCount = 10)]"; + } + + + + [Theory] + [MemberData(nameof(ByValueMarshalAttributeOnPinnedMarshalledTypes))] + [MemberData(nameof(ByValueMarshalAttributeOnValueTypes))] + [MemberData(nameof(ByValueMarshalAttributeOnCustomCollections))] + public async Task VerifyByValueMarshallingAttributeUsageInfoMessages(string id, string source, DiagnosticResult[] diagnostics) + { + _ = id; + VerifyComInterfaceGenerator.Test test = new(referenceAncillaryInterop: false) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck, + }; + test.DisabledDiagnostics.Remove(GeneratorDiagnostics.Ids.NotRecommendedGeneratedComInterfaceUsage); + test.ExpectedDiagnostics.AddRange(diagnostics); + await test.RunAsync(); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs index b013d8c26c4599..700797fcb3e888 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -12,12 +13,26 @@ namespace ComInterfaceGenerator.Unit.Tests { internal partial class CodeSnippets { + internal static IComInterfaceAttributeProvider GetAttributeProvider(GeneratorKind generator) + => generator switch + { + GeneratorKind.VTableIndexStubGenerator => new VirtualMethodIndexAttributeProvider(), + GeneratorKind.ComInterfaceGeneratorManagedObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ManagedObjectWrapper), + GeneratorKind.ComInterfaceGeneratorComObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ComObjectWrapper), + GeneratorKind.ComInterfaceGenerator => new GeneratedComInterfaceAttributeProvider(), + _ => throw new UnreachableException(), + }; + private readonly IComInterfaceAttributeProvider _attributeProvider; public CodeSnippets(IComInterfaceAttributeProvider attributeProvider) { _attributeProvider = attributeProvider; } + public CodeSnippets(GeneratorKind generator) : this(GetAttributeProvider(generator)) + { + } + private string VirtualMethodIndex( int index, bool? ImplicitThisParameter = null, @@ -49,6 +64,51 @@ private string UnmanagedCallConv(Type[]? CallConvs = null) + arguments + "]"; } + public static string GetCustomCollectionType(string elementName) => $"StatelessCollectionAllShapes<{elementName}>"; + + public const string CustomCollectionAndMarshaller = CustomCollectionDefinition + CustomCollectionAllShapesMarshaller; + public const string CustomCollectionDefinition = """ + internal class StatelessCollectionAllShapes + { + public T _field; + } + """; + public const string CustomCollectionAllShapesMarshaller = """ + [ContiguousCollectionMarshaller] + [CustomMarshaller(typeof(StatelessCollectionAllShapes<>), MarshalMode.Default, typeof(StatelessCollectionAllShapesMarshaller<,>))] + internal unsafe static class StatelessCollectionAllShapesMarshaller where TUnmanagedElement : unmanaged + { + public static void Free(TUnmanagedElement* unmanaged) { } + + // ToUnmanaged + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(StatelessCollectionAllShapes managed, out int numElements) + => throw null; + public static System.ReadOnlySpan GetManagedValuesSource(StatelessCollectionAllShapes managed) // Can throw exceptions + => throw null; + public static System.Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) // Can throw exceptions + => throw null; + public static ref TUnmanagedElement* GetPinnableReference(StatelessCollectionAllShapes managed) + => throw null; + + // Caller Allocated buffer ToUnmanaged + public static int BufferSize { get; } = 10; + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(StatelessCollectionAllShapes managed, System.Span buffer, out int numElements) + => throw null; + + // ToManaged + public static StatelessCollectionAllShapes AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) + => throw null; + public static System.Span GetManagedValuesDestination(StatelessCollectionAllShapes managed) + => throw null; + public static System.ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) + => throw null; + + //ToManaged Guaranteed marshalling + public static StatelessCollectionAllShapes AllocateContainerForManagedElementsFinally(TUnmanagedElement* unmanaged, int numElements) + => throw null; + } + """; + public static readonly string DisableRuntimeMarshalling = "[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]"; public static readonly string UsingSystemRuntimeInteropServicesMarshalling = "using System.Runtime.InteropServices.Marshalling;"; public const string IntMarshaller = """ diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj index 08ca1a56fa43c8..beda4af3a72283 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj @@ -33,6 +33,7 @@ + diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs index 2e4d25da3837e5..331fa54117fb04 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs @@ -3,9 +3,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices.Marshalling; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -14,6 +12,7 @@ using Microsoft.Interop; using Microsoft.Interop.UnitTests; using Xunit; +using static Microsoft.Interop.UnitTests.TestUtils; using StringMarshalling = System.Runtime.InteropServices.StringMarshalling; using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; @@ -21,11 +20,6 @@ namespace ComInterfaceGenerator.Unit.Tests { public class CompileFails { - private static string ID( - [CallerLineNumber] int lineNumber = 0, - [CallerFilePath] string? filePath = null) - => TestUtils.GetFileLineName(lineNumber, filePath); - public static IEnumerable ComInterfaceGeneratorSnippetsToCompile() { CodeSnippets codeSnippets = new(new GeneratedComInterfaceAttributeProvider()); @@ -54,19 +48,9 @@ public async Task ValidateComInterfaceGeneratorSnippets(string id, string source await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source, expectedDiagnostics); } - private static IComInterfaceAttributeProvider GetAttributeProvider(GeneratorKind generator) - => generator switch - { - GeneratorKind.VTableIndexStubGenerator => new VirtualMethodIndexAttributeProvider(), - GeneratorKind.ComInterfaceGeneratorManagedObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ManagedObjectWrapper), - GeneratorKind.ComInterfaceGeneratorComObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ComObjectWrapper), - GeneratorKind.ComInterfaceGenerator => new GeneratedComInterfaceAttributeProvider(), - _ => throw new UnreachableException(), - }; - public static IEnumerable InvalidUnmanagedToManagedCodeSnippetsToCompile(GeneratorKind generator) { - CodeSnippets codeSnippets = new(GetAttributeProvider(generator)); + CodeSnippets codeSnippets = new(generator); string safeHandleMarshallerDoesNotSupportManagedToUnmanaged = string.Format(SR.ManagedToUnmanagedMissingRequiredMarshaller, "global::System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller"); string safeHandleMarshallerDoesNotSupportUnmanagedToManaged = string.Format(SR.UnmanagedToManagedMissingRequiredMarshaller, "global::System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller"); @@ -98,7 +82,7 @@ public static IEnumerable InvalidUnmanagedToManagedCodeSnippetsToCompi DiagnosticResult invalidReturnTypeDiagnostic = VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) .WithLocation(0) .WithArguments(marshallerDoesNotSupportManagedToUnmanaged, "Method"); - CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); + CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(CodeSnippets.GetAttributeProvider(generator))); yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyOutParameter, new[] { invalidManagedToUnmanagedParameterDiagnostic } }; yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyReturnValue, new[] { invalidReturnTypeDiagnostic } }; yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.ByValueInParameter, new[] { invalidUnmanagedToManagedParameterDiagnostic } }; @@ -113,7 +97,7 @@ public static IEnumerable StringMarshallingCodeSnippets(GeneratorKind string CustomTypeSpecifiedWithNoStringMarshallingCustom = SR.InvalidStringMarshallingConfigurationNotCustom; string StringMarshallingMustMatchBase = SR.GeneratedComInterfaceStringMarshallingMustMatchBase; - CodeSnippets codeSnippets = new(GetAttributeProvider(generator)); + CodeSnippets codeSnippets = new(generator); (StringMarshalling, Type?) utf8Marshalling = (StringMarshalling.Utf8, null); (StringMarshalling, Type?) utf16Marshalling = (StringMarshalling.Utf16, null); (StringMarshalling, Type?) customUtf16Marshalling = (StringMarshalling.Custom, typeof(Utf16StringMarshaller)); @@ -342,7 +326,7 @@ public static IEnumerable InvalidManagedToUnmanagedCodeSnippetsToCompi { // Marshallers with only support for their expected places in the signatures in // UnmanagedToManaged marshal modes. - CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); + CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(CodeSnippets.GetAttributeProvider(generator))); yield return new[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyInParameter }; yield return new[] { ID(), customStructMarshallingCodeSnippets.Stateless.ByValueOutParameter }; @@ -543,272 +527,6 @@ public async Task VerifyInterfaceWithLessVisibilityThanInterfaceWarns(string id, await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source, diagnostics); } - public static IEnumerable ByValueMarshalAttributeOnValueTypes() - { - var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); - const string inAttribute = "[{|#1:InAttribute|}]"; - const string outAttribute = "[{|#2:OutAttribute|}]"; - const string paramName = "p"; - string paramNameWithLocation = $$"""{|#0:{{paramName}}|}"""; - var inAttributeIsDefaultDiagnostic = new DiagnosticResult(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(1) - .WithArguments(SR.InOutAttributes, paramName, SR.InAttributeOnlyIsDefault); - - - // [In] is default for all non-pinned marshalled types - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute, "int", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute, "byte", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + "[MarshalAs(UnmanagedType.U4)]", "bool", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + "[MarshalAs(UnmanagedType.U2)]", "char", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic } }; - - // [Out] is not allowed on value types passed by value - there is no indirection for the callee to make visible modifications. - var outAttributeNotSupportedOnValueParameters = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(outAttribute, "int", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters } }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute, "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(outAttribute + "[MarshalAs(UnmanagedType.U4)]", "bool", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(outAttribute, "[MarshalAs(UnmanagedType.U2)] char", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - // [In,Out] should only warn for Out attribute - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute+outAttribute, "int", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters } }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute+outAttribute, "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute + "[MarshalAs(UnmanagedType.U4)]", "bool", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute, "[MarshalAs(UnmanagedType.U2)] char", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - - // Any ref keyword is okay for value types - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("out", "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("out", "byte", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("", "[MarshalAs(UnmanagedType.U2)] out char", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("in", "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("in", "byte", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("", "[MarshalAs(UnmanagedType.U2)] in char", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("ref", "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("ref", "byte", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("", "[MarshalAs(UnmanagedType.U2)] ref char", paramNameWithLocation), - new DiagnosticResult[] {} - }; - } - - public static IEnumerable ByValueMarshalAttributeOnReferenceTypes() - { - var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); - const string inAttribute = "[{|#1:InAttribute|}]"; - const string outAttribute = "[{|#2:OutAttribute|}]"; - const string paramName = "p"; - string paramNameWithLocation = $$"""{|#0:{{paramName}}|}"""; - var inAttributeIsDefaultDiagnostic = new DiagnosticResult(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(1) - .WithArguments(SR.InOutAttributes, paramName, SR.InAttributeOnlyIsDefault); - - // [In] is default - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute, "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute, "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - - var outNotAllowedOnRefTypes = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); - - // [Out] is not allowed on strings - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute, "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { outNotAllowedOnRefTypes } - }; - - // [Out] warns on by value reference types - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute, "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { outNotAllowedOnRefTypes } - }; - - // [In,Out] is fine on classes - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute, "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { outNotAllowedOnRefTypes } - }; - - // All refkinds are okay on classes and strings - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("in", "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("in", "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("out", "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("out", "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("ref", "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("ref", "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { } - }; - } - - public static IEnumerable ByValueMarshalAttributeOnPinnedMarshalledTypes() - { - var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); - const string inAttribute = "[{|#1:InAttribute|}]"; - const string outAttribute = "[{|#2:OutAttribute|}]"; - const string paramName = "p"; - string paramNameWithLocation = $$"""{|#0:{{paramName}}|}"""; - const string constElementCount = @"[MarshalUsing(ConstantElementCount = 10)]"; - var inAttributeIsDefaultDiagnostic = new DiagnosticResult(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(1) - .WithArguments(SR.InOutAttributes, paramName, SR.InAttributeOnlyIsDefault); - - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + constElementCount, "int[]", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic - }}; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute + constElementCount, "char[]", paramNameWithLocation, (StringMarshalling.Utf16, null)), - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - - // bools that are marshalled into a new array are in by default - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType( - inAttribute + "[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeConst = 10)]", - "bool[]", - paramNameWithLocation, - (StringMarshalling.Utf16, null)), - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - // Overriding marshalling with a custom marshaller makes it not pinned - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute, "[MarshalUsing(typeof(IntMarshaller), ElementIndirectionDepth = 1), MarshalUsing(ConstantElementCount = 10)]int[]", paramNameWithLocation) + CodeSnippets.IntMarshaller, - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute + constElementCount, "int[]", paramNameWithLocation), - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute + constElementCount, "char[]", paramNameWithLocation, (StringMarshalling.Utf16, null)), - new DiagnosticResult[] { } - }; - - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute + constElementCount, "int[]", paramNameWithLocation), - new DiagnosticResult[] { } - }; - - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute + constElementCount, "char[]", paramNameWithLocation, (StringMarshalling.Utf16, null)), - new DiagnosticResult[] { } - }; - } - - [Theory] - [MemberData(nameof(ByValueMarshalAttributeOnValueTypes))] - [MemberData(nameof(ByValueMarshalAttributeOnReferenceTypes))] - [MemberData(nameof(ByValueMarshalAttributeOnPinnedMarshalledTypes))] - public async Task VerifyByValueMarshallingAttributeUsage(string id, string source, DiagnosticResult[] diagnostics) - { - _ = id; - VerifyComInterfaceGenerator.Test test = new(referenceAncillaryInterop: false) - { - TestCode = source, - TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck, - }; - test.ExpectedDiagnostics.AddRange(diagnostics); - await test.RunAsync(); - } - [Fact] public async Task VerifyNonPartialInterfaceWarns() { @@ -967,7 +685,7 @@ partial interface {|#0:J|} public static IEnumerable CountParameterIsOutSnippets() { - var g = GetAttributeProvider(GeneratorKind.ComInterfaceGenerator); + var g = CodeSnippets.GetAttributeProvider(GeneratorKind.ComInterfaceGenerator); CodeSnippets a = new(g); DiagnosticResult returnValueDiag = new DiagnosticResult(GeneratorDiagnostics.SizeOfInCollectionMustBeDefinedAtCallReturnValue) .WithLocation(1) diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs index 4d1ec3a5d2c7dd..cd065f54a48c0b 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs @@ -1,10 +1,6 @@ // 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.Diagnostics; -using Microsoft.CodeAnalysis.Testing; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -15,6 +11,10 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace Microsoft.Interop.UnitTests @@ -51,6 +51,10 @@ public enum TestTargetFramework public static class TestUtils { + public static string ID( + [CallerLineNumber] int lineNumber = 0, + [CallerFilePath] string? filePath = null) + => TestUtils.GetFileLineName(lineNumber, filePath); internal static string GetFileLineName( [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string? filePath = null) @@ -298,7 +302,7 @@ public void Stop() int count = Interlocked.Decrement(ref _count); if (count == 0) { - Environment.SetEnvironmentVariable(EnvVarName, null); + Environment.SetEnvironmentVariable(EnvVarName, null); } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs new file mode 100644 index 00000000000000..e632481d52109f --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs @@ -0,0 +1,135 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.Interop; +using Xunit; +using static Microsoft.Interop.UnitTests.TestUtils; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; + +namespace LibraryImportGenerator.UnitTests +{ + public class ByValueContentsMarshalling + { + public static IEnumerable ByValueMarshalAttributeOnValueTypes() + { + CodeSnippets.ByValueParameterWithModifier("int[]", "In"); + + const string In = "InAttribute"; + const string Out = "OutAttribute"; + const string InOut = "InAttribute, OutAttribute"; + const string paramName = "p"; + const string MarshalUsingUtf16 = "MarshalUsing(typeof(Utf16StringMarshaller))"; + + var diagnostic = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails); + var outAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); + var inAttributeIsNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InAttributeNotSupportedOnByValueParameters, paramName); + var inOutAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InOutAttributeNotSupportedOnByValueParameters, paramName); + + DiagnosticResult[] InIsNotSupported = [inAttributeIsNotSupported]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int", In), InIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte", In), InIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string", In + " , " + MarshalUsingUtf16), InIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct", In, CodeSnippets.IntStructAndMarshaller), InIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass", In, CodeSnippets.IntClassAndMarshaller), InIsNotSupported }; + + DiagnosticResult[] OutIsNotSupported = [outAttributeNotSupported]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int", Out), OutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte", Out), OutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string", Out + " , " + MarshalUsingUtf16), OutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct", Out, CodeSnippets.IntStructAndMarshaller), OutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass", Out, CodeSnippets.IntClassAndMarshaller), OutIsNotSupported }; + + DiagnosticResult[] InOutIsNotSupported = [inOutAttributeNotSupported]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int", InOut), InOutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte", InOut), InOutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string", InOut + " , " + MarshalUsingUtf16), InOutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct", InOut, CodeSnippets.IntStructAndMarshaller), InOutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass", InOut, CodeSnippets.IntClassAndMarshaller), InOutIsNotSupported }; + + var inAndOutNotAllowedWithRefKind = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p"); + DiagnosticResult[] InAndOutNotAllowedWithRefKind = [inAndOutNotAllowedWithRefKind]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("in int", In), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", In), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", InOut), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("out int", Out), InAndOutNotAllowedWithRefKind }; + } + + public static IEnumerable ByValueMarshalAttributeOnArrays() + { + CodeSnippets.ByValueParameterWithModifier("int[]", "In"); + + const string In = "InAttribute"; + const string Out = "OutAttribute"; + const string InOut = "InAttribute, OutAttribute"; + const string MarshalUsingUtf16 = "MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)"; + const string Count = "MarshalUsing(ConstantElementCount = 10)"; + DiagnosticResult[] None = []; + + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int[]", string.Join(',', Count, In)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte[]", string.Join(',', Count, In)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string[]", string.Join(',', Count, In, MarshalUsingUtf16)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct[]", string.Join(',', Count, In), CodeSnippets.IntStructAndMarshaller), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass[]", string.Join(',', Count, In), CodeSnippets.IntClassAndMarshaller), None }; + + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int[]", string.Join(',', Count, Out)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte[]", string.Join(',', Count, Out)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string[]", string.Join(',', Count, Out, MarshalUsingUtf16)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct[]", string.Join(',', Count, Out), CodeSnippets.IntStructAndMarshaller), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass[]", string.Join(',', Count, Out), CodeSnippets.IntClassAndMarshaller), None }; + + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int[]", string.Join(',', Count, InOut)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte[]", string.Join(',', Count, InOut)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string[]", string.Join(',', Count, InOut, MarshalUsingUtf16)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct[]", string.Join(',', Count, InOut), CodeSnippets.IntStructAndMarshaller), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass[]", string.Join(',', Count, InOut), CodeSnippets.IntClassAndMarshaller), None }; + + DiagnosticResult preferAttributes = new DiagnosticResult(GeneratorDiagnostics.LibraryImportUsageDoesNotFollowBestPractices) + .WithArguments(SR.PreferExplicitInOutAttributesOnArrays) + .WithLocation(0); + DiagnosticResult[] PreferAttributes = [preferAttributes]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int[]", Count), PreferAttributes }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte[]", Count), PreferAttributes }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string[]", string.Join(',', Count, MarshalUsingUtf16)), PreferAttributes }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct[]", Count, CodeSnippets.IntStructAndMarshaller), PreferAttributes }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass[]", Count, CodeSnippets.IntClassAndMarshaller), PreferAttributes }; + + var inAndOutNotAllowedWithRefKind = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p"); + DiagnosticResult[] InAndOutNotAllowedWithRefKind = [inAndOutNotAllowedWithRefKind]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("in int[]", string.Join(',', Count, In)), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int[]", string.Join(',', Count, In)), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int[]", string.Join(',', Count, In, Out)), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("out int[]", string.Join(',', Count, Out)), InAndOutNotAllowedWithRefKind }; + } + + + [Theory] + [MemberData(nameof(ByValueMarshalAttributeOnValueTypes))] + [MemberData(nameof(ByValueMarshalAttributeOnArrays))] + public async Task VerifyByValueMarshallingAttributeUsageInfoMessages(string id, string source, DiagnosticResult[] diagnostics) + { + _ = id; + VerifyCS.Test test = new(referenceAncillaryInterop: false) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck, + }; + test.DisabledDiagnostics.Remove(GeneratorDiagnostics.Ids.NotRecommendedGeneratedComInterfaceUsage); + test.ExpectedDiagnostics.AddRange(diagnostics); + await test.RunAsync(); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs index e1039f70a90ef9..19832861a38aaa 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs @@ -986,6 +986,22 @@ out int pOutSize } """; + public const string IntClassAndMarshaller = IntClassDefinition + IntClassMarshallerDefinition; + public const string IntClassDefinition = """ + internal struct IntClass + { + public int Field; + } + """; + public const string IntClassMarshallerDefinition = """ + [CustomMarshaller(typeof(IntClass), MarshalMode.Default, typeof(IntClassMarshaller))] + internal static class IntClassMarshaller + { + public static nint ConvertToUnmanaged(IntClass managed) => (nint)0; + public static IntClass ConvertToManaged(nint unmanaged) => default; + } + """; + public const string IntStructAndMarshaller = IntStructDefinition + IntStructMarshallerDefinition; public const string IntStructDefinition = """ internal struct IntStruct diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs index ffb3fb5c6a14ba..2d278dc6237de2 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs @@ -350,56 +350,6 @@ public static IEnumerable CodeSnippetsToCompile() .WithArguments("MarshalAsAttribute", "t") }}; - // Unsupported [In, Out] attributes usage - - // By ref with [In, Out] attributes - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("in int", "In"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") - } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", "In"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") - } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", "In, Out"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") - } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("out int", "Out"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") - } }; - - // By value non-array with [In, Out] attributes - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#1:In|}"), new [] { - VerifyCS.Diagnostic(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(1) - .WithArguments(SR.InOutAttributes, "p", SR.InAttributeOnlyIsDefault) - .WithSeverity(DiagnosticSeverity.Info) - } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("Out"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, "p") - } }; - - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("In, Out"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, "p") - } }; - // LCIDConversion yield return new object[] { ID(), CodeSnippets.LCIDConversionAttribute, new[] { VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) @@ -832,13 +782,6 @@ public static IEnumerable CodeSnippetsToCompile() .WithLocation(1) .WithArguments("ref return", "Basic.RefReadonlyReturn()"), } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#10:In|}"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(10) - .WithArguments("[In] and [Out] attributes", "p", SR.InAttributeOnlyIsDefault) - } }; } [Theory] diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs index 438d589b2c29d0..5d37fffd52a5b6 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.Interop.UnitTests; using Xunit; -using GeneratorDiagnostics = Microsoft.Interop.GeneratorDiagnostics; using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; namespace LibraryImportGenerator.UnitTests @@ -744,28 +743,5 @@ public NoChangeTest(TestTargetFramework framework) return (newCompilation, diagnostics); } } - - public static IEnumerable ByValueMarshalKindSnippets() - { - // Blittable array - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#10:Out|}"), new DiagnosticResult[] { } }; - - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#10:In|}, {|#11:Out|}"), new DiagnosticResult[] { } }; - - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#10:In|}"), new DiagnosticResult[] { - VerifyCS.Diagnostic(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(10) - .WithArguments("[In] and [Out] attributes", "p", SR.InAttributeOnlyIsDefault) - } }; - } - - [MemberData(nameof(ByValueMarshalKindSnippets))] - [Theory] - public async Task ValidateDiagnosticsForUnnecessaryByValueMarshalKindAttributes(string id, string source, DiagnosticResult[] diagnostics) - { - _ = id; - await VerifyCS.VerifySourceGeneratorAsync(source, diagnostics); - } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/SharedTypes.csproj b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/SharedTypes.csproj index 63256a99295555..790a5e3f05a366 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/SharedTypes.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/SharedTypes.csproj @@ -11,7 +11,8 @@ - + +