Adds tests to ensure expected diagnostics are produced for interfaces with a Guid and generic interfaces.
Copies attributes on methods on base methods to the generated shadowing method definitions.
Adds Test type with a CompilationVerifier field of Action to make it easier to make one-off tests that verify compilations without making a new type.
--- /dev/null
+// 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;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+
+namespace Microsoft.Interop
+{
+ /// <summary>
+ /// Provides the info necessary for copying an attribute from user code to generated code.
+ /// </summary>
+ internal sealed record AttributeInfo(ManagedTypeInfo Type, SequenceEqualImmutableArray<string> Arguments)
+ {
+ internal AttributeSyntax GenerateSyntax()
+ {
+ return Attribute((NameSyntax)Type.Syntax, AttributeArgumentList(SeparatedList(Arguments.Select(arg => AttributeArgument(ParseExpression(arg))))));
+ }
+ internal AttributeListSyntax GenerateAttributeList()
+ {
+ return AttributeList(SingletonSeparatedList(GenerateSyntax()));
+ }
+ internal static AttributeInfo From(AttributeData attribute)
+ {
+ var type = ManagedTypeInfo.CreateTypeInfoForTypeSymbol(attribute.AttributeClass);
+ var args = attribute.ConstructorArguments.Select(ca => ca.ToCSharpString());
+ return new(type, args.ToSequenceEqualImmutableArray());
+ }
+ }
+}
// and is not marked static or sealed
if (syntax.TypeParameterList is not null)
{
- return (null, Diagnostic.Create(
- GeneratorDiagnostics.InvalidAttributedMethodSignature,
- syntax.Identifier.GetLocation(),
- symbol.Name));
+ // Verify the interface has no generic types or defined implementation
+ // and is not marked static or sealed
+ if (syntax.TypeParameterList is not null)
+ {
+ return (null, Diagnostic.Create(
+ GeneratorDiagnostics.InvalidAttributedInterfaceGenericNotSupported,
+ syntax.Identifier.GetLocation(),
+ symbol.Name));
+ }
}
// Verify that the types the method is declared in are marked partial.
isEnabledByDefault: true,
description: GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageDescription)));
+ public static readonly DiagnosticDescriptor InvalidAttributedInterfaceGenericNotSupported =
+ new DiagnosticDescriptor(
+ Ids.InvalidGeneratedComInterfaceAttributeUsage,
+ GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageTitle)),
+ GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageDescription)));
+
public static readonly DiagnosticDescriptor MultipleComInterfaceBaseTypes =
new DiagnosticDescriptor(
Ids.MultipleComInterfaceBaseTypes,
<?xml version="1.0" encoding="utf-8"?>
<root>
- <!--
- Microsoft ResX Schema
-
+ <!--
+ Microsoft ResX Schema
+
Version 2.0
-
- The primary goals of this format is to allow a simple XML format
- that is mostly human readable. The generation and parsing of the
- various data types are done through the TypeConverter classes
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
associated with the data types.
-
+
Example:
-
+
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
-
- There are any number of "resheader" rows that contain simple
+
+ There are any number of "resheader" rows that contain simple
name/value pairs.
-
- Each data row contains a name, and value. The row also contains a
- type or mimetype. Type corresponds to a .NET class that support
- text/value conversion through the TypeConverter architecture.
- Classes that don't support this are serialized and stored with the
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
mimetype set.
-
- The mimetype is used for serialized objects, and tells the
- ResXResourceReader how to depersist the object. This is currently not
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
-
- Note - application/x-microsoft.net.object.binary.base64 is the format
- that the ResXResourceWriter will generate, however the reader can
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
-
+
mimetype: application/x-microsoft.net.object.binary.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
-
+
mimetype: application/x-microsoft.net.object.soap.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
- value : The object must be serialized into a byte array
+ value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<value>Method is declared in different partial declaration than the 'GeneratedComInterface' attribute.</value>
</data>
<data name="InvalidGeneratedComInterfaceAttributeUsageDescription" xml:space="preserve">
- <value>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</value>
+ <value>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</value>
</data>
<data name="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute" xml:space="preserve">
<value>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</value>
<data name="MultipleComInterfaceBaseTypesTitle" xml:space="preserve">
<value>Specified interface derives from two or more 'GeneratedComInterfaceAttribute'-attributed interfaces.</value>
</data>
+ <data name="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric" xml:space="preserve">
+ <value>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</value>
+ </data>
<data name="AnalysisFailedDescription" xml:space="preserve">
<value>The analysis required to generate code for this interface or method has failed due to an unexpected code pattern. If you are using new or unconventional syntax, consider using other syntax.</value>
</data>
<data name="AnalysisFailedTitle" xml:space="preserve">
<value>Analysis for generation has failed.</value>
</data>
-</root>
\ No newline at end of file
+</root>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">Rozhraní s atributem GeneratedComInterfaceAttribute musí být částečná a musí určovat identifikátor GUID s atributem System.Runtime.InteropServices.GuidAttribute.</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">Rozhraní s atributem GeneratedComInterfaceAttribute musí být částečná a musí určovat identifikátor GUID s atributem System.Runtime.InteropServices.GuidAttribute.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">Schnittstellen, die mit „GeneratedComInterfaceAttribute“ attribuiert sind, müssen partiell sein und einen GUID mit „System.Runtime.InteropServices.GuidAttribute“ angeben.</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">Schnittstellen, die mit „GeneratedComInterfaceAttribute“ attribuiert sind, müssen partiell sein und einen GUID mit „System.Runtime.InteropServices.GuidAttribute“ angeben.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">Las interfaces atribuidas con 'GeneratedComInterfaceAttribute' deben ser parciales y deben especificar un GUID con 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">Las interfaces atribuidas con 'GeneratedComInterfaceAttribute' deben ser parciales y deben especificar un GUID con 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">Les interfaces sont attribuées à « GeneratedComInterfaceAttribute » doivent être partielles et doivent spécifier un GUID avec « System.Runtime.InteropServices.GuidAttribute ».</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">Les interfaces sont attribuées à « GeneratedComInterfaceAttribute » doivent être partielles et doivent spécifier un GUID avec « System.Runtime.InteropServices.GuidAttribute ».</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">Le interfacce attribuite con 'GeneratedComInterfaceAttribute' devono essere parziali e devono specificare un GUID con 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">Le interfacce attribuite con 'GeneratedComInterfaceAttribute' devono essere parziali e devono specificare un GUID con 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">'GeneratedComInterfaceAttribute' の属性を持つインターフェイスは部分的である必要があり、'System.Runtime.InteropServices.GuidAttribute' で GUID を指定する必要があります。</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">'GeneratedComInterfaceAttribute' の属性を持つインターフェイスは部分的である必要があり、'System.Runtime.InteropServices.GuidAttribute' で GUID を指定する必要があります。</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">'GeneratedComInterfaceAttribute'(으)로 지정된 인터페이스는 부분적이어야 하며 'System.Runtime.InteropServices.GuidAttribute'을(를) 이용하여 GUID를 지정해야 합니다.</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">'GeneratedComInterfaceAttribute'(으)로 지정된 인터페이스는 부분적이어야 하며 'System.Runtime.InteropServices.GuidAttribute'을(를) 이용하여 GUID를 지정해야 합니다.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">Interfejsy z atrybutem „GeneratedComInterfaceAttribute” muszą być częściowe i muszą określać identyfikator GUID z atrybutem „System.Runtime.InteropServices.GuidAttribute”.</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">Interfejsy z atrybutem „GeneratedComInterfaceAttribute” muszą być częściowe i muszą określać identyfikator GUID z atrybutem „System.Runtime.InteropServices.GuidAttribute”.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">As interfaces atribuídas com "GeneratedComInterfaceAttribute" devem ser parciais e devem especificar um GUID com "System.Runtime.InteropServices.GuidAttribute".</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">As interfaces atribuídas com "GeneratedComInterfaceAttribute" devem ser parciais e devem especificar um GUID com "System.Runtime.InteropServices.GuidAttribute".</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">Интерфейсы с атрибутом GeneratedComInterfaceAttribute должны быть частичными и должны указывать GUID с помощью System.Runtime.InteropServices.GuidAttribute.</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">Интерфейсы с атрибутом GeneratedComInterfaceAttribute должны быть частичными и должны указывать GUID с помощью System.Runtime.InteropServices.GuidAttribute.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">'GeneratedComInterfaceAttribute' özniteliğine sahip arabirimler kısmi olmalı ve 'System.Runtime.InteropServices.GuidAttribute' ile bir GUID belirtilmelidir.</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">'GeneratedComInterfaceAttribute' özniteliğine sahip arabirimler kısmi olmalı ve 'System.Runtime.InteropServices.GuidAttribute' ile bir GUID belirtilmelidir.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">通过 “GeneratedComInterfaceAttribute” 特性化的接口必须是部分的,并且必须使用 “System.Runtime.InteropServices.GuidAttribute” 指定 GUID。</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">通过 “GeneratedComInterfaceAttribute” 特性化的接口必须是部分的,并且必须使用 “System.Runtime.InteropServices.GuidAttribute” 指定 GUID。</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
- <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
- <target state="translated">屬性為 'GeneratedComInterfaceAttribute' 的介面必須是部分介面,而且必須指定具有 'System.Runtime.InteropServices.GuidAttribute' 的 GUID。</target>
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial, non-generic, and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="needs-review-translation">屬性為 'GeneratedComInterfaceAttribute' 的介面必須是部分介面,而且必須指定具有 'System.Runtime.InteropServices.GuidAttribute' 的 GUID。</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageInterfaceIsGeneric">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is generic.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
intObj.SetInt(2);
Assert.Equal(2, intObj.GetInt());
}
-
- [Fact]
- public unsafe void DerivedInterfaceTypeProvidesBaseInterfaceUnmanagedToManagedMembers()
- {
- // Make sure that we have the correct derived and base types here.
- Assert.Contains(typeof(IGetAndSetInt), typeof(IDerivedComInterface).GetInterfaces());
-
- IIUnknownDerivedDetails baseInterfaceDetails = StrategyBasedComWrappers.DefaultIUnknownInterfaceDetailsStrategy.GetIUnknownDerivedDetails(typeof(IGetAndSetInt).TypeHandle);
- IIUnknownDerivedDetails derivedInterfaceDetails = StrategyBasedComWrappers.DefaultIUnknownInterfaceDetailsStrategy.GetIUnknownDerivedDetails(typeof(IDerivedComInterface).TypeHandle);
-
- var numBaseMethods = typeof(IGetAndSetInt).GetMethods().Length;
-
- var numPointersToCompare = 3 + numBaseMethods;
-
- var expected = new ReadOnlySpan<nint>(baseInterfaceDetails.ManagedVirtualMethodTable, numPointersToCompare);
- var actual = new ReadOnlySpan<nint>(derivedInterfaceDetails.ManagedVirtualMethodTable, numPointersToCompare);
-
- Assert.True(expected.SequenceEqual(actual));
- }
-
- [Fact]
- public unsafe void CallBaseInterfaceMethod_EnsureQiCalledOnce()
- {
- var cw = new SingleQIComWrapper();
- var derivedImpl = new DerivedImpl();
- var nativeObj = cw.GetOrCreateComInterfaceForObject(derivedImpl, CreateComInterfaceFlags.None);
- var obj = cw.GetOrCreateObjectForComInstance(nativeObj, CreateObjectFlags.None);
- IDerivedComInterface iface = (IDerivedComInterface)obj;
-
- Assert.Equal(3, iface.GetInt());
- iface.SetInt(5);
- Assert.Equal(5, iface.GetInt());
-
- // https://github.com/dotnet/runtime/issues/85795
- //Assert.Equal("myName", iface.GetName());
- //iface.SetName("updated");
- //Assert.Equal("updated", iface.GetName());
-
- var qiCallCountObj = obj.GetType().GetRuntimeProperties().Where(p => p.Name == "IUnknownStrategy").Single().GetValue(obj);
- var countQi = (SingleQIComWrapper.CountQI)qiCallCountObj;
- Assert.Equal(1, countQi.QiCallCount);
- }
-
- [GeneratedComClass]
- partial class DerivedImpl : IDerivedComInterface
- {
- int data = 3;
- string myName = "myName";
-
- public int GetInt() => data;
-
- public string GetName() => myName;
-
- public void SetInt(int n) => data = n;
-
- public void SetName(string name) => myName = name;
- }
-
- class SingleQIComWrapper : StrategyBasedComWrappers
- {
- public class CountQI : IIUnknownStrategy
- {
- public CountQI(IIUnknownStrategy iUnknown) => _iUnknownStrategy = iUnknown;
- private IIUnknownStrategy _iUnknownStrategy;
- public int QiCallCount = 0;
- public unsafe void* CreateInstancePointer(void* unknown) => _iUnknownStrategy.CreateInstancePointer(unknown);
- public unsafe int QueryInterface(void* instancePtr, in Guid iid, out void* ppObj)
- {
- QiCallCount++;
- return _iUnknownStrategy.QueryInterface(instancePtr, in iid, out ppObj);
- }
- public unsafe int Release(void* instancePtr) => _iUnknownStrategy.Release(instancePtr);
- }
-
- protected override IIUnknownStrategy GetOrCreateIUnknownStrategy()
- => new CountQI(base.GetOrCreateIUnknownStrategy());
- }
}
--- /dev/null
+// 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.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+using System.Text;
+using System.Threading.Tasks;
+using SharedTypes.ComInterfaces;
+using Xunit;
+
+namespace ComInterfaceGenerator.Tests
+{
+ public partial class IDerivedTests
+ {
+ [Fact]
+ public unsafe void DerivedInterfaceTypeProvidesBaseInterfaceUnmanagedToManagedMembers()
+ {
+ // Make sure that we have the correct derived and base types here.
+ Assert.Contains(typeof(IGetAndSetInt), typeof(IDerived).GetInterfaces());
+
+ IIUnknownDerivedDetails baseInterfaceDetails = StrategyBasedComWrappers.DefaultIUnknownInterfaceDetailsStrategy.GetIUnknownDerivedDetails(typeof(IGetAndSetInt).TypeHandle);
+ IIUnknownDerivedDetails derivedInterfaceDetails = StrategyBasedComWrappers.DefaultIUnknownInterfaceDetailsStrategy.GetIUnknownDerivedDetails(typeof(IDerived).TypeHandle);
+
+ var numBaseMethods = typeof(IGetAndSetInt).GetMethods().Length;
+
+ var numPointersToCompare = 3 + numBaseMethods;
+
+ var expected = new ReadOnlySpan<nint>(baseInterfaceDetails.ManagedVirtualMethodTable, numPointersToCompare);
+ var actual = new ReadOnlySpan<nint>(derivedInterfaceDetails.ManagedVirtualMethodTable, numPointersToCompare);
+
+ Assert.True(expected.SequenceEqual(actual));
+ }
+ [Fact]
+ public unsafe void CallBaseInterfaceMethod_EnsureQiCalledOnce()
+ {
+ var cw = new SingleQIComWrapper();
+ var derivedImpl = new DerivedImpl();
+ var nativeObj = cw.GetOrCreateComInterfaceForObject(derivedImpl, CreateComInterfaceFlags.None);
+ var obj = cw.GetOrCreateObjectForComInstance(nativeObj, CreateObjectFlags.None);
+ IDerived iface = (IDerived)obj;
+
+ Assert.Equal(3, iface.GetInt());
+ iface.SetInt(5);
+ Assert.Equal(5, iface.GetInt());
+
+ // https://github.com/dotnet/runtime/issues/85795
+ //Assert.Equal("myName", iface.GetName());
+ //iface.SetName("updated");
+ //Assert.Equal("updated", iface.GetName());
+
+ var qiCallCountObj = obj.GetType().GetRuntimeProperties().Where(p => p.Name == "IUnknownStrategy").Single().GetValue(obj);
+ var countQi = (SingleQIComWrapper.CountQI)qiCallCountObj;
+ Assert.Equal(1, countQi.QiCallCount);
+ }
+
+ [GeneratedComClass]
+ partial class DerivedImpl : IDerived
+ {
+ int data = 3;
+ string myName = "myName";
+ public void DoThingWithString([MarshalUsing(typeof(Utf16StringMarshaller))] string name) => throw new NotImplementedException();
+
+ public int GetInt() => data;
+
+ public string GetName() => myName;
+
+ public void SetInt(int n) => data = n;
+
+ public void SetName(string name) => myName = name;
+ }
+
+ /// <summary>
+ /// Used to ensure that QI is only called once when calling base methods on a derived COM interface
+ /// </summary>
+ class SingleQIComWrapper : StrategyBasedComWrappers
+ {
+ public class CountQI : IIUnknownStrategy
+ {
+ public CountQI(IIUnknownStrategy iUnknown) => _iUnknownStrategy = iUnknown;
+ private IIUnknownStrategy _iUnknownStrategy;
+ public int QiCallCount = 0;
+ public unsafe void* CreateInstancePointer(void* unknown) => _iUnknownStrategy.CreateInstancePointer(unknown);
+ public unsafe int QueryInterface(void* instancePtr, in Guid iid, out void* ppObj)
+ {
+ QiCallCount++;
+ return _iUnknownStrategy.QueryInterface(instancePtr, in iid, out ppObj);
+ }
+ public unsafe int Release(void* instancePtr) => _iUnknownStrategy.Release(instancePtr);
+ }
+
+ protected override IIUnknownStrategy GetOrCreateIUnknownStrategy()
+ => new CountQI(base.GetOrCreateIUnknownStrategy());
+ }
+ }
+}
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Testing;
+using Microsoft.Interop;
using Microsoft.Interop.UnitTests;
using Xunit;
await VerifySourceGeneratorAsync(source, "I", "J");
}
+ [Fact]
+ public async Task ValidateAttributesAreCopiedToShadowingMethods()
+ {
+ var source = $$"""
+ using System;
+ using System.Runtime.InteropServices;
+ using System.Runtime.InteropServices.Marshalling;
+
+ namespace Test
+ {
+ [GeneratedComInterface]
+ [Guid("EA4319EA-AE9A-4261-B42D-BB027AD81F5F")]
+ partial interface IFoo
+ {
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("message")]
+ void Bar();
+ }
+
+ [GeneratedComInterface]
+ [Guid("8A501001-02CA-490A-AA23-0ECC646F07A3")]
+ partial interface IDerivedIface : IFoo
+ {
+ }
+ }
+ """;
+
+ var test = new VerifyCompilationTest<Microsoft.Interop.ComInterfaceGenerator>(false)
+ {
+ TestCode = source,
+ TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck | TestBehaviors.SkipGeneratedCodeCheck,
+ CompilationVerifier = VerifyCompilation
+ };
+ await test.RunAsync();
+
+ static void VerifyCompilation(Compilation comp)
+ {
+ Assert.True(comp.GetTypeByMetadataName("Test.IFoo")
+ ?.GetMembers()
+ .Where(m => m.Kind == SymbolKind.Method && m.Name == "Bar")
+ .SingleOrDefault()
+ ?.GetAttributes()
+ .Any(att => att.AttributeClass?.Name == nameof(RequiresUnreferencedCodeAttribute)));
+ }
+ }
+
private static async Task VerifySourceGeneratorAsync(string source, params string[] typeNames)
{
GeneratedShapeTest test = new(typeNames)
await test.RunAsync();
}
+
class GeneratedShapeTest : VerifyCS.Test
{
private readonly string[] _typeNames;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
-
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Testing;
+using Microsoft.Interop;
using Microsoft.Interop.UnitTests;
using Xunit;
-
using System.Diagnostics;
-
using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier<Microsoft.Interop.ComInterfaceGenerator>;
-using Microsoft.Interop;
+using Newtonsoft.Json.Bson;
+using System.Diagnostics.CodeAnalysis;
namespace ComInterfaceGenerator.Unit.Tests
{
.WithArguments("The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type 'global::Marshaller' does not support it.", "value");
await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source, expectedDiagnostic);
}
+
+ [Fact]
+ public async Task ValidateInterfaceWithoutGuidWarns()
+ {
+ var source = $$"""
+
+ [System.Runtime.InteropServices.Marshalling.GeneratedComInterface]
+ partial interface {|#0:IFoo|}
+ {
+ void Method();
+ }
+
+ """;
+ DiagnosticResult expectedDiagnostic = VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.InvalidAttributedInterfaceMissingGuidAttribute)
+ .WithLocation(0).WithArguments("IFoo");
+
+ await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source, expectedDiagnostic);
+ }
+
+ [Fact]
+ public async Task VerifyGenericInterfaceCreatesDiagnostic()
+ {
+ var source = $$"""
+
+ namespace Tests
+ {
+ public interface IFoo1<T>
+ {
+ void Method();
+ }
+
+ [System.Runtime.InteropServices.Marshalling.GeneratedComInterface]
+ [System.Runtime.InteropServices.Guid("36722BA8-A03B-406E-AFE6-27AA2F7AC032")]
+ partial interface {|#0:IFoo2|}<T>
+ {
+ void Method();
+ }
+ }
+ """;
+
+ DiagnosticResult expectedDiagnostic = VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.InvalidAttributedInterfaceGenericNotSupported)
+ .WithLocation(0).WithArguments("IFoo2");
+
+ await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source, expectedDiagnostic);
+ }
}
}
--- /dev/null
+// 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;
+using Microsoft.Interop.UnitTests;
+
+namespace ComInterfaceGenerator.Unit.Tests
+{
+ internal class VerifyCompilationTest<T> : Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier<T>.Test
+ where T : new()
+ {
+ public required Action<Compilation> CompilationVerifier { get; init; }
+
+ public VerifyCompilationTest(TestTargetFramework targetFramework) : base(targetFramework)
+ {
+ }
+
+ public VerifyCompilationTest(bool referenceAncillaryInterop) : base(referenceAncillaryInterop)
+ {
+ }
+
+ protected override void VerifyFinalCompilation(Compilation compilation) => CompilationVerifier(compilation);
+ }
+}
{
[GeneratedComInterface]
[Guid(_guid)]
- internal partial interface IDerivedComInterface : IGetAndSetInt
+ internal partial interface IDerived : IGetAndSetInt
{
void SetName([MarshalUsing(typeof(Utf16StringMarshaller))] string name);
{
[GeneratedComInterface]
[Guid(_guid)]
- internal partial interface Empty
+ internal partial interface IEmpty
{
public const string _guid = "95D19F50-F2D8-4E61-884B-0A9162EA4646";
}