From 1630725383caefafadec57ae0bf34fba312ab602 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 12 Jan 2023 11:48:25 -0800 Subject: [PATCH] Create analyzer in ComInterfaceGenerator to enforce the generator is used with IUnknown only (#78189) Creates an analyzer that warns if the GeneratedComInterfaceAttribute is used with InterfaceTypeAttribute that has an argument that is not 'InterfaceIsIUnknown' Co-authored-by: Jeremy Koritzinsky Co-authored-by: Elinor Fung --- docs/project/list-of-diagnostics.md | 10 + .../Analyzers/AnalyzerDiagnostics.cs | 33 + .../GeneratedComInterfaceAttributeAnalyzer.cs | 91 +++ .../GeneratorDiagnostics.cs | 4 +- .../Resources/Strings.resx | 6 + .../Resources/xlf/Strings.cs.xlf | 10 + .../Resources/xlf/Strings.de.xlf | 10 + .../Resources/xlf/Strings.es.xlf | 10 + .../Resources/xlf/Strings.fr.xlf | 10 + .../Resources/xlf/Strings.it.xlf | 10 + .../Resources/xlf/Strings.ja.xlf | 10 + .../Resources/xlf/Strings.ko.xlf | 10 + .../Resources/xlf/Strings.pl.xlf | 10 + .../Resources/xlf/Strings.pt-BR.xlf | 10 + .../Resources/xlf/Strings.ru.xlf | 10 + .../Resources/xlf/Strings.tr.xlf | 10 + .../Resources/xlf/Strings.zh-Hans.xlf | 10 + .../Resources/xlf/Strings.zh-Hant.xlf | 10 + .../TypeNames.cs | 6 + .../GeneratedComInterfaceAttribute.cs | 42 ++ .../ComInterfaceGenerator.Unit.Tests.csproj | 8 +- .../GeneratedComInterfaceAnalyzerTests.cs | 618 ++++++++++++++++++ .../Verifiers/CSharpAnalyzerVerifier.cs | 0 .../Verifiers/CSharpCodeFixVerifier.cs | 4 +- .../Verifiers/CSharpVerifierHelper.cs | 0 .../LibraryImportGenerator.Unit.Tests.csproj | 8 +- 26 files changed, 954 insertions(+), 6 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AnalyzerDiagnostics.cs create mode 100644 src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/GeneratedComInterfaceAttributeAnalyzer.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedComInterfaceAttribute.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs rename src/libraries/System.Runtime.InteropServices/tests/{LibraryImportGenerator.UnitTests => Common}/Verifiers/CSharpAnalyzerVerifier.cs (100%) rename src/libraries/System.Runtime.InteropServices/tests/{LibraryImportGenerator.UnitTests => Common}/Verifiers/CSharpCodeFixVerifier.cs (99%) rename src/libraries/System.Runtime.InteropServices/tests/{LibraryImportGenerator.UnitTests => Common}/Verifiers/CSharpVerifierHelper.cs (100%) diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index 6fdd33421b408..c0d4a51a99a88 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -192,6 +192,16 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL | __`SYSLIB1078`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | | __`SYSLIB1079`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | | __`SYSLIB1080`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1081`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1082`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1083`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1084`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1085`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1086`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1087`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1088`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1089`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* | +| __`SYSLIB1090`__ | Invalid 'GeneratedComInterfaceAttribute' usage | ### Diagnostic Suppressions (`SYSLIBSUPPRESS****`) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AnalyzerDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AnalyzerDiagnostics.cs new file mode 100644 index 0000000000000..beccfb8abcc31 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AnalyzerDiagnostics.cs @@ -0,0 +1,33 @@ +// 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 Microsoft.CodeAnalysis; +namespace Microsoft.Interop.Analyzers +{ + public static class AnalyzerDiagnostics + { + public static class Ids + { + public const string Prefix = "SYSLIB"; + public const string InvalidGeneratedComAttributeUsage = Prefix + "1090"; + } + + private const string Category = "ComInterfaceGenerator"; + + private static LocalizableResourceString GetResourceString(string resourceName) + { + return new LocalizableResourceString(resourceName, SR.ResourceManager, typeof(FxResources.Microsoft.Interop.ComInterfaceGenerator.SR)); + } + + public static readonly DiagnosticDescriptor InterfaceTypeNotSupported = + new DiagnosticDescriptor( + Ids.InvalidGeneratedComAttributeUsage, + GetResourceString(nameof(SR.InterfaceTypeNotSupportedTitle)), + GetResourceString(nameof(SR.InterfaceTypeNotSupportedMessage)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.InterfaceTypeNotSupportedMessage))); + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/GeneratedComInterfaceAttributeAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/GeneratedComInterfaceAttributeAnalyzer.cs new file mode 100644 index 0000000000000..11a628ddbd0a8 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/GeneratedComInterfaceAttributeAnalyzer.cs @@ -0,0 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.Interop.Analyzers +{ + /// + /// Validates that if an interface has GeneratedComInterfaceAttribute and , + /// the is given a that is supported by the generator. + /// + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class GeneratedComInterfaceAttributeAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(AnalyzerDiagnostics.InterfaceTypeNotSupported); + + public static readonly ImmutableArray SupportedComInterfaceTypes = ImmutableArray.Create(ComInterfaceType.InterfaceIsIUnknown); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSymbolAction((context) => + { + INamedTypeSymbol typeSymbol = (INamedTypeSymbol)context.Symbol; + if (typeSymbol.TypeKind != TypeKind.Interface) + return; + + ImmutableArray customAttributes = typeSymbol.GetAttributes(); + if (customAttributes.Length == 0) + return; + + // Interfaces with both GeneratedComInterfaceAttribute and InterfaceTypeAttribute should only have [InterfaceTypeAttribute(InterfaceIsIUnknown)] + if (GetAttribute(typeSymbol, TypeNames.GeneratedComInterfaceAttribute, out _) + && GetAttribute(typeSymbol, TypeNames.InterfaceTypeAttribute, out AttributeData? comInterfaceAttribute) + && !InterfaceTypeAttributeIsSupported(comInterfaceAttribute, out string unsupportedValue)) + { + context.ReportDiagnostic(comInterfaceAttribute.CreateDiagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported, unsupportedValue)); + } + }, SymbolKind.NamedType); + } + + private static bool InterfaceTypeAttributeIsSupported(AttributeData comInterfaceAttribute, out string argument) + { + if (comInterfaceAttribute.ConstructorArguments.IsEmpty) + { + argument = ""; + return false; + } + TypedConstant ctorArg0 = comInterfaceAttribute.ConstructorArguments[0]; + ComInterfaceType interfaceType; + + argument = ctorArg0.ToCSharpString(); + switch (ctorArg0.Type.ToDisplayString()) + { + case TypeNames.ComInterfaceTypeAttribute: + interfaceType = (ComInterfaceType)ctorArg0.Value; + break; + case TypeNames.System_Int16: + case TypeNames.@short: + interfaceType = (ComInterfaceType)(short)ctorArg0.Value; + break; + default: + return false; + } + + return SupportedComInterfaceTypes.Contains(interfaceType); + } + + private static bool GetAttribute(ISymbol symbol, string attributeDisplayName, [NotNullWhen(true)] out AttributeData? attribute) + { + foreach (AttributeData attr in symbol.GetAttributes()) + { + if (attr.AttributeClass?.ToDisplayString() == attributeDisplayName) + { + attribute = attr; + return true; + } + } + + attribute = null; + return false; + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs index 3aa74a6e37634..fe30702961805 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs @@ -1,11 +1,10 @@ // 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.Syntax; using System; using System.Collections.Generic; using System.Diagnostics; +using Microsoft.CodeAnalysis; namespace Microsoft.Interop { @@ -155,6 +154,7 @@ public class Ids isEnabledByDefault: true, description: GetResourceString(nameof(SR.ConfigurationNotSupportedDescription))); + private readonly List _diagnostics = new List(); public IEnumerable Diagnostics => _diagnostics; diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx index c41cb27d3b5e6..271b72ce92a65 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx @@ -201,4 +201,10 @@ The provided value is not a known flag of the 'ExceptionMarshalling' enum. + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.cs.xlf index ebf04d8a6c01e..a58d1773f2781 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.cs.xlf @@ -37,6 +37,16 @@ Určenou konfiguraci nepodporují zdrojem generovaná volání P/Invokes. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. Metoda {0} je obsažena v typu {1}, který není označen jako „partial“. Generování zdrojů volání P/Invoke bude metodu {0} ignorovat. diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.de.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.de.xlf index 27db7e68cb401..73e6b39fae8b6 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.de.xlf @@ -37,6 +37,16 @@ Die angegebene Konfiguration wird von quellgenerierten P/Invokes nicht unterstützt. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. Die Methode \"{0}\" ist in einem Typ \"{1}\" enthalten, der nicht als \"partiell\" gekennzeichnet ist. Die P/Invoke-Quellgenerierung ignoriert die Methode \"{0}\". diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.es.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.es.xlf index 422b0c610a9af..05bd15bde6781 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.es.xlf @@ -37,6 +37,16 @@ La configuración especificada no está admitida por P/Invokes de un generador de código fuente. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. El método “{0}” está contenido en un tipo “{1}” que no está marcado como “partial”. La generación de código fuente P/Invoke omitirá el método “{0}”. diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.fr.xlf index aefc6600087f2..5e9f0e4a694cf 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.fr.xlf @@ -37,6 +37,16 @@ La configuration spécifiée n’est pas prise en charge par les P/Invokes générés par la source. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. La méthode « {0} » est contenue dans un type « {1} » qui n’est pas marqué comme étant « partial ». La génération source P/Invoke ignore la méthode « {0} ». diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.it.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.it.xlf index 3d795e49f3e10..25abe5c5d84b8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.it.xlf @@ -37,6 +37,16 @@ La configurazione specificata non è supportata dai P/Invoke generati dall'origine. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. Il metodo '{0}' è contenuto in un tipo '{1}' non contrassegnato come 'partial'. Durante la generazione dell'origine P/Invoke il metodo '{0}' verrà ignorato. diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ja.xlf index 796458cd39156..137d5d0e1b945 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ja.xlf @@ -37,6 +37,16 @@ 指定された構成は、ソースで生成された P/Invoke ではサポートされていません。 + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. メソッド '{0}' は、'partial' とマークされていない型 '{1}' に含まれています。P/Invoke ソース生成はメソッド '{0}' を無視します。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ko.xlf index eb1e24c587705..9c07e95d8411e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ko.xlf @@ -37,6 +37,16 @@ 지정된 구성은 소스 생성 P/Invoke에서 지원되지 않습니다. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. 메서드 '{0}'은(는) 'partial'로 표시되지 않은 '{1}' 형식에 포함되어 있습니다. P/Invoke 소스 생성은 '{0}' 메서드를 무시합니다. diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pl.xlf index 5f115e3e0dfaa..b3fe029e117fd 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pl.xlf @@ -37,6 +37,16 @@ Określona konfiguracja nie jest obsługiwana przez funkcję P/Invokes generowaną przez źródło. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. Metoda „{0}” jest zawarta w typie „{1}”, który nie jest oznaczony jako „częściowy”. Generowanie źródła funkcji P/Invoke zignoruje metodę „{0}”. diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pt-BR.xlf index 10ee4a30e7764..0fceac94f1316 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pt-BR.xlf @@ -37,6 +37,16 @@ A configuração especificada não tem suporte de P/Invokes gerados pela origem. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. O '{0}' está contido em um tipo '{1}' que não está marcado como 'partial'. A geração de origem P/Invoke ignorará o método '{0}'. diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ru.xlf index 9c55fe0a365ad..eb0be5f461d94 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ru.xlf @@ -37,6 +37,16 @@ Указанная конфигурация не поддерживается в P/Invoke с созданием источника. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. Метод \"{0}\" содержится в типе \"{1}\", который не помечен как \"partial\". Метод \"{0}\" будет игнорироваться при создании источника в P/Invoke. diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.tr.xlf index 85ea807e01470..f845049177465 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.tr.xlf @@ -37,6 +37,16 @@ Belirtilen yapılandırma, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor. + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. '{0}'metodu, 'partial' olarak işaretlenmemiş olan bir '{1}' türünün içinde yer alıyor. P/Invoke kaynak oluşturma işlemi, '{0}' metodunu yok sayacak. diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hans.xlf index eec0d86150c9b..89dd896236fca 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hans.xlf @@ -37,6 +37,16 @@ 源生成的 P/Invoke 不支持指定的配置。 + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. 方法“{0}”包含在未标记为 “partial” 的类型“{1}”中。P/Invoke 源生成将忽略方法“{0}”。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hant.xlf index fc5a34c7a8c87..783348d05a1ea 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hant.xlf @@ -37,6 +37,16 @@ 来源產生的 P/Invokes 不支援指定的設定。 + + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'. + + + + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + 'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type. + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. 方法 '{0}' 包含在未標示為 'partial' 的類型'{1}'中。產生 P/Invoke 来源會忽略方法'{0}'。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs index b7284126f5baa..9b4effbb55ed8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs @@ -53,6 +53,9 @@ public static class TypeNames public const string System_Type = "System.Type"; + public const string System_Int16 = "System.Int16"; + public const string @short = "short"; + public const string System_Runtime_InteropServices_StructLayoutAttribute = "System.Runtime.InteropServices.StructLayoutAttribute"; public const string System_Runtime_InteropServices_MarshalAsAttribute = "System.Runtime.InteropServices.MarshalAsAttribute"; @@ -98,6 +101,9 @@ public static string MarshalEx(InteropGenerationOptions options) public const string System_Runtime_InteropServices_DynamicInterfaceCastableImplementationAttribute = "System.Runtime.InteropServices.DynamicInterfaceCastableImplementationAttribute"; + public const string GeneratedComInterfaceAttribute = "System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute"; + public const string InterfaceTypeAttribute = "System.Runtime.InteropServices.InterfaceTypeAttribute"; + public const string ComInterfaceTypeAttribute = "System.Runtime.InteropServices.ComInterfaceType"; public const string System_Runtime_InteropServices_ComWrappers_ComInterfaceDispatch = "System.Runtime.InteropServices.ComWrappers.ComInterfaceDispatch"; } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedComInterfaceAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedComInterfaceAttribute.cs new file mode 100644 index 0000000000000..dfd26a12c6edc --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedComInterfaceAttribute.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.InteropServices.Marshalling +{ + public interface IComObjectWrapper { } + + public class ComWrappers { } + + public class ComObject : IDynamicInterfaceCastable, IComObjectWrapper + { + public bool IsInterfaceImplemented(RuntimeTypeHandle th, bool b) => true; + public RuntimeTypeHandle GetInterfaceImplementation(RuntimeTypeHandle th) => th; + // Implement support for casting through IUnknown. + // No thread-affinity aware support. + // No IDispatch support. + // No aggregation support. + } + + public abstract class GeneratedComWrappersBase : ComWrappers + { + } + + [AttributeUsage(AttributeTargets.Interface)] + public class GeneratedComInterfaceAttribute : Attribute + { + public GeneratedComInterfaceAttribute(Type comWrappersType) + => (ComWrappersType) = (comWrappersType); + + public GeneratedComInterfaceAttribute(Type comWrappersType, bool generateManagedObjectWrapper, bool generateComObjectWrapper) + => (ComWrappersType, GenerateManagedObjectWrapper, GenerateComObjectWrapper) + = (comWrappersType, generateManagedObjectWrapper, generateComObjectWrapper); + + public Type ComWrappersType { get; } + + public bool GenerateManagedObjectWrapper { get; } = true; + + public bool GenerateComObjectWrapper { get; } = true; + + public bool ExportInterfaceDefinition { get; } + } +} 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 1fd768c257647..24f484a369624 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 @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent) @@ -19,6 +19,12 @@ Link="Common\CustomStructMarshallingCodeSnippets.cs" /> + + + diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs new file mode 100644 index 0000000000000..7f34b242e2bed --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs @@ -0,0 +1,618 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Microsoft.Interop; +using Microsoft.Interop.Analyzers; +using Xunit; + +using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpAnalyzerVerifier; + +namespace ComInterfaceGenerator.Unit.Tests +{ + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] + public class GeneratedComInterfaceAnalyzerTests + { + static string _usings = $$""" + #pragma warning disable CS8019 + using System.Runtime.InteropServices.Marshalling; + using System.Runtime.InteropServices; + #pragma warning restore CS8019 + """; + + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] + public class InterfaceHasInterfaceTypeAttributeOnly + { + [Fact] + public async Task IUnknown() + { + string snippet = $$$""" + + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IUnknownShort() + { + string snippet = $$$""" + + [InterfaceTypeAttribute((short)1)] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IDispatch() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IDispatchShort() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute((short)2)] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IInspectable() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIInspectable)] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IInspectableShort() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute((short)3)] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IDual() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IDualShort() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute((short)0)] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] + public class InterfaceHasGeneratedComInterfaceAttributeOnly + { + [Fact] + public async Task Test() + { + string snippet = + $$$""" + + [GeneratedComInterface(typeof(MyComWrappers))] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] + public class InterfaceHasGeneratedComInterfaceAttributeAndInterfaceTypeAttribute + { + [Fact] + public async Task IUnknown() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + [GeneratedComInterface(typeof(MyComWrappers))] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IUnknownShort() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute((short)1)] + [GeneratedComInterface(typeof(MyComWrappers))] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IDispatch() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)|}] + [GeneratedComInterface(typeof(MyComWrappers))] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsIDispatch))); + } + + [Fact] + public async Task IDispatchShort() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute((short)2)|}] + [GeneratedComInterface(typeof(MyComWrappers))] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments("2")); + } + + [Fact] + public async Task IInspectable() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIInspectable)|}] + [GeneratedComInterface(typeof(MyComWrappers))] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsIInspectable))); + } + + [Fact] + public async Task IInspectableShort() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute((short)3)|}] + [GeneratedComInterface(typeof(MyComWrappers))] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments("3")); + } + + [Fact] + public async Task IDual() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)|}] + [GeneratedComInterface(typeof(MyComWrappers))] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsDual))); + } + + [Fact] + public async Task IDualShort() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute((short)0)|}] + [GeneratedComInterface(typeof(MyComWrappers))] + interface IFoo + { + void Bar() {} + } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments("0")); + } + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] + public class PartialInterfaceHasGeneratedComInterfaceAttributeAndInterfaceTypeAttribute + { + [Fact] + public async Task IUnknown() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + partial interface IFoo + { + void Bar() {} + } + + [GeneratedComInterface(typeof(MyComWrappers))] + partial interface IFoo { } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IUnknownShort() + { + string snippet = + $$$""" + + [InterfaceTypeAttribute((short)1)] + partial interface IFoo + { + void Bar() {} + } + + [GeneratedComInterface(typeof(MyComWrappers))] + partial interface IFoo { } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync(_usings + snippet); + } + + [Fact] + public async Task IDispatch() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)|}] + partial interface IFoo + { + void Bar() {} + } + + [GeneratedComInterface(typeof(MyComWrappers))] + partial interface IFoo { } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsIDispatch))); + } + + [Fact] + public async Task IDispatchShort() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute((short)2)|}] + partial interface IFoo + { + void Bar() {} + } + + [GeneratedComInterface(typeof(MyComWrappers))] + partial interface IFoo { } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments("2")); + } + + [Fact] + public async Task IInspectable() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIInspectable)|}] + partial interface IFoo + { + void Bar() {} + } + + [GeneratedComInterface(typeof(MyComWrappers))] + partial interface IFoo { } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsIInspectable))); + } + + [Fact] + public async Task IInspectableShort() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute((short)3)|}] + partial interface IFoo + { + void Bar() {} + } + + [GeneratedComInterface(typeof(MyComWrappers))] + partial interface IFoo { } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments("3")); + } + + [Fact] + public async Task IDual() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)|}] + partial interface IFoo + { + void Bar() {} + } + + [GeneratedComInterface(typeof(MyComWrappers))] + partial interface IFoo { } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsDual))); + } + + [Fact] + public async Task IDualShort() + { + string snippet = + $$$""" + + [{|#0:InterfaceTypeAttribute((short)0)|}] + partial interface IFoo + { + void Bar() {} + } + + [GeneratedComInterface(typeof(MyComWrappers))] + partial interface IFoo { } + + public partial class MyComWrappers : GeneratedComWrappersBase + { + } + + """; + await VerifyCS.VerifyAnalyzerAsync( + _usings + snippet, + VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) + .WithLocation(0) + .WithArguments("0")); + } + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpAnalyzerVerifier.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpAnalyzerVerifier.cs similarity index 100% rename from src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpAnalyzerVerifier.cs rename to src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpAnalyzerVerifier.cs diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpCodeFixVerifier.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs similarity index 99% rename from src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpCodeFixVerifier.cs rename to src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs index 22ea6f49aa782..00f03f13ec2fa 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpCodeFixVerifier.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Immutable; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Microsoft; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; @@ -169,7 +169,7 @@ protected override CompilationWithAnalyzers CreateCompilationWithAnalyzers(Compi new CompilationWithAnalyzersOptions( options, onAnalyzerException: null, - concurrentAnalysis: true, + concurrentAnalysis: !Debugger.IsAttached, logAnalyzerExecutionTime: true, reportSuppressedDiagnostics: false, analyzerExceptionFilter: ex => diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpVerifierHelper.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs similarity index 100% rename from src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Verifiers/CSharpVerifierHelper.cs rename to src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/LibraryImportGenerator.Unit.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/LibraryImportGenerator.Unit.Tests.csproj index 4158ee4011344..af79b40f82074 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/LibraryImportGenerator.Unit.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/LibraryImportGenerator.Unit.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent) @@ -17,6 +17,12 @@ Link="Common\CustomStructMarshallingCodeSnippets.cs" /> + + +