From: Jeremy Koritzinsky Date: Fri, 9 Jun 2023 03:36:25 +0000 (-0700) Subject: Add analyzers and code-fixes to help adoption of source-generated COM (#87223) X-Git-Tag: accepted/tizen/unified/riscv/20231226.055536~1744 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4d52032d9596c6fa74bac4e2c7e8e6d7653bd4ab;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Add analyzers and code-fixes to help adoption of source-generated COM (#87223) * Add first pass of the "convert to generated COM interface" analyzer and add tests for the various other analyzers we are going to introduce. * Get all analyzer-specific components of the "convert" tests passing. * Implement all interface-attribute-level changes in the code fixer. * Add bool marshalling insertion logic to the fixer. * Add support for removing shadowing members from interfaces. * Rename fixer * ActiveIssue the new tests * Implement basic AddGeneratedComClass analyzer/fixer * Add ComHosting + GeneratedComInterface analyzer implementation. * Implement the "runtime COM APIs with source-generated COM types" analyzer. * Factor out a base class from the ConvertToLibraryImportFixer so we can share it with the ComInterfaceGenerator-family of fixers. * Move more of the ConvertToLibraryImportFixer to use SyntaxGenerator APIs instead of dropping to C#-specific syntax APIs (improves consistency throughout our code fixes) * Move support for specifying explicit boolean marshalling rules up to the base class. * Move the code fixes in ComInterfaceGenerator over to using the ConvertToSourceGeneratedInteropFixer base type. * Remove use of multicasted delegates and use a more traditional "array of delegates" model. * Do some refactoring to move more into the new fixer base class. * Remove custom CodeAction-derived types now that we have a record type to represent fixes from the subclasses. * Make sure we make types and containing types partial * Fix negative test. * Add tests for transitive interface inheritance and add iids. * Change bool parsing for internal parsing and add warning annotation text. Update diagnostics list md. --- diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index d6783d8..eae2823 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -212,10 +212,10 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL | __`SYSLIB1093`__ | _`SYSLIB1092`-`SYSLIB1099` reserved for Microsoft.Interop.ComInteropGenerator._ | | __`SYSLIB1094`__ | _`SYSLIB1092`-`SYSLIB1099` reserved for Microsoft.Interop.ComInteropGenerator._ | | __`SYSLIB1095`__ | _`SYSLIB1092`-`SYSLIB1099` reserved for Microsoft.Interop.ComInteropGenerator._ | -| __`SYSLIB1096`__ | _`SYSLIB1092`-`SYSLIB1099` reserved for Microsoft.Interop.ComInteropGenerator._ | -| __`SYSLIB1097`__ | _`SYSLIB1092`-`SYSLIB1099` reserved for Microsoft.Interop.ComInteropGenerator._ | -| __`SYSLIB1098`__ | _`SYSLIB1092`-`SYSLIB1099` reserved for Microsoft.Interop.ComInteropGenerator._ | -| __`SYSLIB1099`__ | _`SYSLIB1092`-`SYSLIB1099` reserved for Microsoft.Interop.ComInteropGenerator._ | +| __`SYSLIB1096`__ | Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time | +| __`SYSLIB1097`__ | This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. | +| __`SYSLIB1098`__ | .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. | +| __`SYSLIB1099`__ | COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime | | __`SYSLIB1100`__ | Configuration binding generator: type is not supported. | | __`SYSLIB1101`__ | Configuration binding generator: property on type is not supported. | | __`SYSLIB1102`__ | Configuration binding generator: project's language version must be at least C# 11.| diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AddGeneratedComClassAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AddGeneratedComClassAnalyzer.cs new file mode 100644 index 0000000..29e817b --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AddGeneratedComClassAnalyzer.cs @@ -0,0 +1,59 @@ +// 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.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; +using static Microsoft.Interop.Analyzers.AnalyzerDiagnostics; + +namespace Microsoft.Interop.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class AddGeneratedComClassAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(AddGeneratedComClassAttribute); + + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + + context.RegisterCompilationStartAction(context => + { + var generatedComClassAttributeType = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComClassAttribute); + var generatedComInterfaceAttributeType = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComInterfaceAttribute); + + if (generatedComClassAttributeType is null || generatedComInterfaceAttributeType is null) + { + return; + } + + context.RegisterSymbolAction(context => + { + INamedTypeSymbol type = (INamedTypeSymbol)context.Symbol; + if (type.GetAttributes().Any(attr => generatedComClassAttributeType.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))) + { + return; + } + + // Only direct people to put the GeneratedComClassAttribute on classes. + if (type.TypeKind != TypeKind.Class) + { + return; + } + + foreach (var iface in type.AllInterfaces) + { + if (iface.GetAttributes().Any(attr => generatedComInterfaceAttributeType.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))) + { + context.ReportDiagnostic(type.CreateDiagnostic(AddGeneratedComClassAttribute, type.Name)); + return; + } + } + }, SymbolKind.NamedType); + }); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AddGeneratedComClassFixer.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AddGeneratedComClassFixer.cs new file mode 100644 index 0000000..716b18c --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AddGeneratedComClassFixer.cs @@ -0,0 +1,62 @@ +// 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.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Simplification; + +namespace Microsoft.Interop.Analyzers +{ + [ExportCodeFixProvider(LanguageNames.CSharp), Shared] + public class AddGeneratedComClassFixer : ConvertToSourceGeneratedInteropFixer + { + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AnalyzerDiagnostics.Ids.AddGeneratedComClassAttribute); + + protected override string BaseEquivalenceKey => nameof(AddGeneratedComClassFixer); + + private static Task AddGeneratedComClassAsync(DocumentEditor editor, SyntaxNode node) + { + editor.ReplaceNode(node, (node, gen) => + { + var attribute = gen.Attribute(gen.TypeExpression(editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComClassAttribute)).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation)); + var updatedNode = gen.AddAttributes(node, attribute); + var declarationModifiers = gen.GetModifiers(updatedNode); + if (!declarationModifiers.IsPartial) + { + updatedNode = gen.WithModifiers(updatedNode, declarationModifiers.WithPartial(true)); + } + return updatedNode; + }); + + MakeNodeParentsPartial(editor, node); + + return Task.CompletedTask; + } + + protected override Func CreateFixForSelectedOptions(SyntaxNode node, ImmutableDictionary selectedOptions) + { + return (editor, _) => AddGeneratedComClassAsync(editor, node); + } + + protected override string GetDiagnosticTitle(ImmutableDictionary selectedOptions) + { + bool allowUnsafe = selectedOptions.TryGetValue(Option.AllowUnsafe, out var allowUnsafeOption) && allowUnsafeOption is Option.Bool(true); + + return allowUnsafe + ? SR.AddGeneratedComClassAttributeTitle + : SR.AddGeneratedComClassAddUnsafe; + } + + protected override ImmutableDictionary ParseOptionsFromDiagnostic(Diagnostic diagnostic) + { + return ImmutableDictionary.Empty; + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AnalyzerDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AnalyzerDiagnostics.cs index beccfb8..53f778c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AnalyzerDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/AnalyzerDiagnostics.cs @@ -11,9 +11,19 @@ namespace Microsoft.Interop.Analyzers { public const string Prefix = "SYSLIB"; public const string InvalidGeneratedComAttributeUsage = Prefix + "1090"; + public const string ConvertToGeneratedComInterface = Prefix + "1096"; + public const string AddGeneratedComClassAttribute = Prefix + "1097"; + public const string ComHostingDoesNotSupportGeneratedComInterface = Prefix + "1098"; + public const string RuntimeComApisDoNotSupportSourceGeneratedCom = Prefix + "1099"; } - private const string Category = "ComInterfaceGenerator"; + public static class Metadata + { + public const string MayRequireAdditionalWork = nameof(MayRequireAdditionalWork); + public const string AddStringMarshalling = nameof(AddStringMarshalling); + } + + private const string Category = "Interoperability"; private static LocalizableResourceString GetResourceString(string resourceName) { @@ -29,5 +39,45 @@ namespace Microsoft.Interop.Analyzers DiagnosticSeverity.Error, isEnabledByDefault: true, description: GetResourceString(nameof(SR.InterfaceTypeNotSupportedMessage))); + + public static readonly DiagnosticDescriptor ConvertToGeneratedComInterface = + new DiagnosticDescriptor( + Ids.ConvertToGeneratedComInterface, + GetResourceString(nameof(SR.ConvertToGeneratedComInterfaceTitle)), + GetResourceString(nameof(SR.ConvertToGeneratedComInterfaceMessage)), + Category, + DiagnosticSeverity.Info, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.ConvertToGeneratedComInterfaceDescription))); + + public static readonly DiagnosticDescriptor AddGeneratedComClassAttribute = + new DiagnosticDescriptor( + Ids.AddGeneratedComClassAttribute, + GetResourceString(nameof(SR.AddGeneratedComClassAttributeTitle)), + GetResourceString(nameof(SR.AddGeneratedComClassAttributeMessage)), + Category, + DiagnosticSeverity.Info, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.AddGeneratedComClassAttributeDescription))); + + public static readonly DiagnosticDescriptor ComHostingDoesNotSupportGeneratedComInterface = + new DiagnosticDescriptor( + Ids.ComHostingDoesNotSupportGeneratedComInterface, + GetResourceString(nameof(SR.ComHostingDoesNotSupportGeneratedComInterfaceTitle)), + GetResourceString(nameof(SR.ComHostingDoesNotSupportGeneratedComInterfaceMessage)), + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.ComHostingDoesNotSupportGeneratedComInterfaceDescription))); + + public static readonly DiagnosticDescriptor RuntimeComApisDoNotSupportSourceGeneratedCom = + new DiagnosticDescriptor( + Ids.RuntimeComApisDoNotSupportSourceGeneratedCom, + GetResourceString(nameof(SR.RuntimeComApisDoNotSupportSourceGeneratedComTitle)), + GetResourceString(nameof(SR.RuntimeComApisDoNotSupportSourceGeneratedComMessage)), + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.RuntimeComApisDoNotSupportSourceGeneratedComDescription))); } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ComHostingDoesNotSupportGeneratedComInterfaceAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ComHostingDoesNotSupportGeneratedComInterfaceAnalyzer.cs new file mode 100644 index 0000000..4efd732 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ComHostingDoesNotSupportGeneratedComInterfaceAnalyzer.cs @@ -0,0 +1,71 @@ +// 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.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; +using Microsoft.CodeAnalysis.Operations; +using static Microsoft.Interop.Analyzers.AnalyzerDiagnostics; + +namespace Microsoft.Interop.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ComHostingDoesNotSupportGeneratedComInterfaceAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(ComHostingDoesNotSupportGeneratedComInterface); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterCompilationStartAction(context => + { + if (!context.Options.AnalyzerConfigOptionsProvider.GlobalOptions.TryGetValue("build_property.EnableComHosting", out string? enableComHosting) + || !bool.TryParse(enableComHosting, out bool enableComHostingValue) + || !enableComHostingValue) + { + return; + } + + INamedTypeSymbol? generatedComClassAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComClassAttribute); + INamedTypeSymbol? generatedComInterfaceAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComInterfaceAttribute); + INamedTypeSymbol? comVisibleAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.System_Runtime_InteropServices_ComVisibleAttribute)!; + + if (generatedComClassAttribute is null || generatedComInterfaceAttribute is null || comVisibleAttribute is null) + { + return; + } + + context.RegisterOperationAction(context => + { + IAttributeOperation attr = (IAttributeOperation)context.Operation; + if (attr.Operation is not IObjectCreationOperation ctor + || !comVisibleAttribute.Equals(ctor.Type, SymbolEqualityComparer.Default) + || ctor.Arguments[0].Value.ConstantValue.Value is not true) + { + return; + } + + INamedTypeSymbol containingType = (INamedTypeSymbol)context.ContainingSymbol; + + if (containingType.GetAttributes().Any(attr => generatedComClassAttribute.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))) + { + context.ReportDiagnostic(context.ContainingSymbol.CreateDiagnostic(ComHostingDoesNotSupportGeneratedComInterface, context.ContainingSymbol.Name)); + return; + } + + foreach (var iface in containingType.AllInterfaces) + { + if (iface.GetAttributes().Any(attr => generatedComInterfaceAttribute.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))) + { + context.ReportDiagnostic(context.ContainingSymbol.CreateDiagnostic(ComHostingDoesNotSupportGeneratedComInterface, context.ContainingSymbol.Name)); + return; + } + } + }, OperationKind.Attribute); + }); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ConvertComImportToGeneratedComInterfaceAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ConvertComImportToGeneratedComInterfaceAnalyzer.cs new file mode 100644 index 0000000..1449bcc --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ConvertComImportToGeneratedComInterfaceAnalyzer.cs @@ -0,0 +1,233 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; +using static Microsoft.Interop.Analyzers.AnalyzerDiagnostics; + +namespace Microsoft.Interop.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ConvertComImportToGeneratedComInterfaceAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(ConvertToGeneratedComInterface); + + private static readonly HashSet s_unsupportedTypeNames = new() + { + "global::System.Runtime.InteropServices.CriticalHandle", + "global::System.Runtime.InteropServices.HandleRef", + "global::System.Text.StringBuilder" + }; + + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + + context.RegisterCompilationStartAction(context => + { + INamedTypeSymbol? interfaceTypeAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.InterfaceTypeAttribute)!; + INamedTypeSymbol? generatedComInterfaceAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComInterfaceAttribute); + + if (generatedComInterfaceAttribute is null) + { + return; + } + + TargetFrameworkSettings targetFramework = context.Options.AnalyzerConfigOptionsProvider.GlobalOptions.GetTargetFrameworkSettings(); + var env = new StubEnvironment( + context.Compilation, + targetFramework.TargetFramework, + targetFramework.Version, + context.Compilation.SourceModule.GetAttributes().Any(attr => attr.AttributeClass.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_SkipLocalsInitAttribute)); + + context.RegisterSymbolAction(context => + { + INamedTypeSymbol type = (INamedTypeSymbol)context.Symbol; + AttributeData? interfaceTypeAttributeData = type.GetAttributes().FirstOrDefault(a => a.AttributeClass.Equals(interfaceTypeAttribute, SymbolEqualityComparer.Default)); + if (type is not { TypeKind: TypeKind.Interface, IsComImport: true } + || interfaceTypeAttributeData.ConstructorArguments.Length == 1 && (int)interfaceTypeAttributeData.ConstructorArguments[0].Value != (int)ComInterfaceType.InterfaceIsIUnknown) + { + return; + } + + bool mayRequireAdditionalWork = false; + bool hasStrings = false; + if (type.DeclaringSyntaxReferences.Length > 1) + { + mayRequireAdditionalWork = true; + } + + foreach (var method in type.GetMembers().OfType().Where(m => !m.IsStatic && m.IsAbstract)) + { + // Ignore types with methods with unsupported returns + if (method.ReturnsByRef || method.ReturnsByRefReadonly) + return; + // Run a basic conversion check like we do for ConvertToLibraryImportAttributeAnalyzer to determine if there will be warnings after the fix. + + // Use the method signature to do some of the work the generator will do after conversion. + // If any diagnostics or failures to marshal are reported, then mark this diagnostic with a property signifying that it may require + // later user work. + AnyDiagnosticsSink diagnostics = new(); + AttributeData comImportAttribute = type.GetAttributes().First(attr => attr.AttributeClass.ToDisplayString() == TypeNames.System_Runtime_InteropServices_ComImportAttribute); + SignatureContext targetSignatureContext = SignatureContext.Create( + method, + CreateComImportMarshallingInfoParser(env, diagnostics, method, comImportAttribute), + env, + typeof(ConvertComImportToGeneratedComInterfaceAnalyzer).Assembly); + + var managedToUnmanagedFactory = ComInterfaceGeneratorHelpers.CreateGeneratorFactory(env, MarshalDirection.ManagedToUnmanaged); + var unmanagedToManagedFactory = ComInterfaceGeneratorHelpers.CreateGeneratorFactory(env, MarshalDirection.UnmanagedToManaged); + + mayRequireAdditionalWork = diagnostics.AnyDiagnostics; + bool anyExplicitlyUnsupportedInfo = false; + + var managedToNativeStubCodeContext = new ManagedToNativeStubCodeContext(env.TargetFramework, env.TargetFrameworkVersion, "return", "nativeReturn"); + var nativeToManagedStubCodeContext = new NativeToManagedStubCodeContext(env.TargetFramework, env.TargetFrameworkVersion, "return", "nativeReturn"); + + var forwarder = new Forwarder(); + // We don't actually need the bound generators. We just need them to be attempted to be bound to determine if the generator will be able to bind them. + BoundGenerators generators = BoundGenerators.Create(targetSignatureContext.ElementTypeInformation, new CallbackGeneratorFactory((info, context) => + { + if (s_unsupportedTypeNames.Contains(info.ManagedType.FullTypeName)) + { + anyExplicitlyUnsupportedInfo = true; + return forwarder; + } + if (HasUnsupportedMarshalAsInfo(info)) + { + anyExplicitlyUnsupportedInfo = true; + return forwarder; + } + if (info.MarshallingAttributeInfo is TrackedMarshallingInfo(TrackedMarshallingInfoAnnotation.ExplicitlyUnsupported, _)) + { + anyExplicitlyUnsupportedInfo = true; + return forwarder; + } + if (info.MarshallingAttributeInfo is TrackedMarshallingInfo(TrackedMarshallingInfoAnnotation annotation, var inner)) + { + if (annotation == TrackedMarshallingInfoAnnotation.String) + { + hasStrings = true; + } + info = info with { MarshallingAttributeInfo = inner }; + } + // Run both factories and collect any binding failures. + _ = unmanagedToManagedFactory.GeneratorFactory.Create(info, nativeToManagedStubCodeContext); + return managedToUnmanagedFactory.GeneratorFactory.Create(info, managedToNativeStubCodeContext); + }), managedToNativeStubCodeContext, forwarder, out var bindingFailures); + + mayRequireAdditionalWork |= bindingFailures.Length > 0; + + if (anyExplicitlyUnsupportedInfo) + { + // If we have any parameters/return value with an explicitly unsupported marshal type or marshalling info, + // don't offer the fix. The amount of work for the user to get to pairity would be too expensive. + return; + } + } + + ImmutableDictionary.Builder properties = ImmutableDictionary.CreateBuilder(); + + properties.Add(AnalyzerDiagnostics.Metadata.MayRequireAdditionalWork, mayRequireAdditionalWork.ToString()); + properties.Add(AnalyzerDiagnostics.Metadata.AddStringMarshalling, hasStrings.ToString()); + + context.ReportDiagnostic(type.CreateDiagnostic(ConvertToGeneratedComInterface, properties.ToImmutable(), type.Name)); + }, SymbolKind.NamedType); + }); + } + + private static MarshallingInfoParser CreateComImportMarshallingInfoParser(StubEnvironment env, IGeneratorDiagnostics diagnostics, IMethodSymbol method, AttributeData unparsedAttributeData) + { + var defaultInfo = new DefaultMarshallingInfo(CharEncoding.Utf16, null); + + var useSiteAttributeParsers = ImmutableArray.Create( + new MarshalAsAttributeParser(env.Compilation, diagnostics, defaultInfo), + new MarshalUsingAttributeParser(env.Compilation, diagnostics)); + + return new MarshallingInfoParser( + diagnostics, + new MethodSignatureElementInfoProvider(env.Compilation, diagnostics, method, useSiteAttributeParsers), + useSiteAttributeParsers, + ImmutableArray.Create( + new MarshalAsAttributeParser(env.Compilation, diagnostics, defaultInfo), + new MarshalUsingAttributeParser(env.Compilation, diagnostics), + new NativeMarshallingAttributeParser(env.Compilation, diagnostics), + new ComInterfaceMarshallingInfoProvider(env.Compilation)), + ImmutableArray.Create( + new SafeHandleMarshallingInfoProvider(env.Compilation, method.ContainingType), + new ExplicitlyUnsupportedMarshallingInfoProvider(), // We don't support arrays, so we don't include the array marshalling info provider. Instead, we include our "explicitly unsupported" provider. + new CharMarshallingInfoProvider(defaultInfo), + new TrackingStringMarshallingInfoProvider(new StringMarshallingInfoProvider(env.Compilation, diagnostics, unparsedAttributeData, defaultInfo)), // We need to mark when we see string types to ensure we offer a code-fix that adds the string marshalling info. + new BooleanMarshallingInfoProvider(), + new BlittableTypeMarshallingInfoProvider(env.Compilation))); + } + + private static bool HasUnsupportedMarshalAsInfo(TypePositionInfo info) + { + if (info.MarshallingAttributeInfo is not MarshalAsInfo(UnmanagedType unmanagedType, _)) + return false; + + return !Enum.IsDefined(typeof(UnmanagedType), unmanagedType) + || unmanagedType == UnmanagedType.CustomMarshaler + || unmanagedType == UnmanagedType.Interface + || unmanagedType == UnmanagedType.IDispatch + || unmanagedType == UnmanagedType.IInspectable + || unmanagedType == UnmanagedType.IUnknown + || unmanagedType == UnmanagedType.SafeArray; + } + + private sealed class AnyDiagnosticsSink : IGeneratorDiagnostics + { + public bool AnyDiagnostics { get; private set; } + public void ReportConfigurationNotSupported(AttributeData attributeData, string configurationName, string? unsupportedValue) => AnyDiagnostics = true; + public void ReportInvalidMarshallingAttributeInfo(AttributeData attributeData, string reasonResourceName, params string[] reasonArgs) => AnyDiagnostics = true; + } + + private sealed class CallbackGeneratorFactory : IMarshallingGeneratorFactory + { + private readonly Func _func; + + public CallbackGeneratorFactory(Func func) + { + _func = func; + } + + public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext context) => _func(info, context); + } + + private enum TrackedMarshallingInfoAnnotation + { + ExplicitlyUnsupported, + String + } + + private sealed record TrackedMarshallingInfo(TrackedMarshallingInfoAnnotation TrackingAnnotation, MarshallingInfo InnerInfo): MarshallingInfo; + + private sealed class TrackingStringMarshallingInfoProvider : ITypeBasedMarshallingInfoProvider + { + private readonly ITypeBasedMarshallingInfoProvider _stringMarshallingInfoProvider; + + public TrackingStringMarshallingInfoProvider(ITypeBasedMarshallingInfoProvider stringMarshallingInfoProvider) + { + _stringMarshallingInfoProvider = stringMarshallingInfoProvider; + } + + public bool CanProvideMarshallingInfoForType(ITypeSymbol type) => type.SpecialType == SpecialType.System_String; + public MarshallingInfo GetMarshallingInfo(ITypeSymbol type, int indirectionDepth, UseSiteAttributeProvider useSiteAttributes, GetMarshallingInfoCallback marshallingInfoCallback) + => new TrackedMarshallingInfo(TrackedMarshallingInfoAnnotation.String, _stringMarshallingInfoProvider.GetMarshallingInfo(type, indirectionDepth, useSiteAttributes, marshallingInfoCallback)); + } + + private sealed class ExplicitlyUnsupportedMarshallingInfoProvider : ITypeBasedMarshallingInfoProvider + { + public bool CanProvideMarshallingInfoForType(ITypeSymbol type) => type is { TypeKind: TypeKind.Array or TypeKind.Delegate } or { SpecialType: SpecialType.System_Array or SpecialType.System_Object }; + public MarshallingInfo GetMarshallingInfo(ITypeSymbol type, int indirectionDepth, UseSiteAttributeProvider useSiteAttributes, GetMarshallingInfoCallback marshallingInfoCallback) => new TrackedMarshallingInfo(TrackedMarshallingInfoAnnotation.ExplicitlyUnsupported, NoMarshallingInfo.Instance); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ConvertComImportToGeneratedComInterfaceFixer.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ConvertComImportToGeneratedComInterfaceFixer.cs new file mode 100644 index 0000000..081b608 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/ConvertComImportToGeneratedComInterfaceFixer.cs @@ -0,0 +1,123 @@ +// 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.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Simplification; + +namespace Microsoft.Interop.Analyzers +{ + [ExportCodeFixProvider(LanguageNames.CSharp), Shared] + public sealed class ConvertComImportToGeneratedComInterfaceFixer : ConvertToSourceGeneratedInteropFixer + { + private const string AddStringMarshallingOption = nameof(AddStringMarshallingOption); + + protected override string BaseEquivalenceKey => "ConvertToGeneratedComInterface"; + + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(AnalyzerDiagnostics.Ids.ConvertToGeneratedComInterface); + + protected override string GetDiagnosticTitle(ImmutableDictionary selectedOptions) + { + return selectedOptions.TryGetValue(Option.AllowUnsafe, out Option allowUnsafeOption) && allowUnsafeOption is Option.Bool(true) + ? SR.ConvertToGeneratedComInterfaceAddUnsafe + : SR.ConvertToGeneratedComInterfaceTitle; + } + + protected override Func CreateFixForSelectedOptions(SyntaxNode node, ImmutableDictionary selectedOptions) + { + bool mayRequireAdditionalWork = selectedOptions.TryGetValue(Option.MayRequireAdditionalWork, out Option mayRequireAdditionalWorkOption) && mayRequireAdditionalWorkOption is Option.Bool(true); + bool addStringMarshalling = selectedOptions.TryGetValue(AddStringMarshallingOption, out Option addStringMarshallingOption) && addStringMarshallingOption is Option.Bool(true); + + return (editor, ct) => ConvertComImportToGeneratedComInterfaceAsync(editor, node, mayRequireAdditionalWork, addStringMarshalling, ct); + } + + protected override ImmutableDictionary ParseOptionsFromDiagnostic(Diagnostic diagnostic) + { + var optionsBuilder = ImmutableDictionary.CreateBuilder(); + // Only add the bool options if they are true. This simplifies our equivalence key and makes testing easier. + if (diagnostic.Properties.TryGetValue(AnalyzerDiagnostics.Metadata.MayRequireAdditionalWork, out string? mayRequireAdditionalWork) && bool.Parse(mayRequireAdditionalWork)) + { + optionsBuilder.Add(Option.MayRequireAdditionalWork, new Option.Bool(true)); + } + if (diagnostic.Properties.TryGetValue(AnalyzerDiagnostics.Metadata.AddStringMarshalling, out string? addStringMarshalling) && bool.Parse(addStringMarshalling)) + { + optionsBuilder.Add(AddStringMarshallingOption, new Option.Bool(true)); + } + return optionsBuilder.ToImmutable(); + } + + private static async Task ConvertComImportToGeneratedComInterfaceAsync(DocumentEditor editor, SyntaxNode node, bool mayRequireAdditionalWork, bool addStringMarshalling, CancellationToken ct) + { + var gen = editor.Generator; + var comp = editor.SemanticModel.Compilation; + var declaringType = editor.SemanticModel.GetDeclaredSymbol(node, ct); + + var generatedComInterfaceAttribute = gen.Attribute(gen.TypeExpression(comp.GetTypeByMetadataName(TypeNames.GeneratedComInterfaceAttribute)).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation)); + + if (addStringMarshalling) + { + generatedComInterfaceAttribute = gen.AddAttributeArguments( + generatedComInterfaceAttribute, + new[] + { + gen.AttributeArgument("StringMarshalling", gen.MemberAccessExpression(gen.DottedName(TypeNames.StringMarshalling), gen.IdentifierName(nameof(StringMarshalling.Custom)))), + gen.AttributeArgument("StringMarshallingCustomType", gen.TypeOfExpression(gen.TypeExpression(comp.GetTypeByMetadataName(TypeNames.BStrStringMarshaller)))) + }); + } + + if (mayRequireAdditionalWork) + { + generatedComInterfaceAttribute = generatedComInterfaceAttribute.WithAdditionalAnnotations( + WarningAnnotation.Create(SR.ConvertComInterfaceMayProduceInvalidCode)); + } + + var comImportAttributeType = comp.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_ComImportAttribute); + + var comImportAttribute = await declaringType.GetAttributes().First(attr => attr.AttributeClass.Equals(comImportAttributeType, SymbolEqualityComparer.Default)).ApplicationSyntaxReference.GetSyntaxAsync(ct).ConfigureAwait(false); + + editor.ReplaceNode(comImportAttribute, generatedComInterfaceAttribute); + + foreach (var member in gen.GetMembers(node)) + { + if (gen.GetDeclarationKind(member) != DeclarationKind.Method) + { + continue; + } + + var declarationModifiers = gen.GetModifiers(member); + + if (declarationModifiers.IsStatic) + { + continue; + } + + if (declarationModifiers.IsNew) + { + // If this is a shadowing method, then we remove it. + // TODO: Do we want to be smarter here and try to match the number of methods to a base interface, etc.? + editor.RemoveNode(member); + continue; + } + + IMethodSymbol method = (IMethodSymbol)editor.SemanticModel.GetDeclaredSymbol(member, ct); + var generatedDeclaration = member; + + generatedDeclaration = AddExplicitDefaultBoolMarshalling(gen, method, generatedDeclaration, "VariantBool"); + editor.ReplaceNode(member, generatedDeclaration); + } + + editor.ReplaceNode(node, (node, gen) => gen.WithModifiers(node, gen.GetModifiers(node).WithPartial(true))); + + MakeNodeParentsPartial(editor, node); + } + + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/GeneratedComInterfaceAttributeAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/GeneratedComInterfaceAttributeAnalyzer.cs index 9779d1e..f3fecba 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/GeneratedComInterfaceAttributeAnalyzer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/GeneratedComInterfaceAttributeAnalyzer.cs @@ -59,7 +59,7 @@ namespace Microsoft.Interop.Analyzers argument = ctorArg0.ToCSharpString(); switch (ctorArg0.Type.ToDisplayString()) { - case TypeNames.ComInterfaceTypeAttribute: + case TypeNames.ComInterfaceType: interfaceType = (ComInterfaceType)ctorArg0.Value; break; case TypeNames.System_Int16: diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/RuntimeComApiUsageWithSourceGeneratedComAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/RuntimeComApiUsageWithSourceGeneratedComAnalyzer.cs new file mode 100644 index 0000000..41b9c65 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Analyzers/RuntimeComApiUsageWithSourceGeneratedComAnalyzer.cs @@ -0,0 +1,176 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; +using Microsoft.CodeAnalysis.Operations; +using static Microsoft.Interop.Analyzers.AnalyzerDiagnostics; + +namespace Microsoft.Interop.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class RuntimeComApiUsageWithSourceGeneratedComAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(RuntimeComApisDoNotSupportSourceGeneratedCom); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterCompilationStartAction(context => + { + INamedTypeSymbol? marshalType = context.Compilation.GetBestTypeByMetadataName(TypeNames.System_Runtime_InteropServices_Marshal); + INamedTypeSymbol? generatedComClassAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComClassAttribute); + INamedTypeSymbol? generatedComInterfaceAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComInterfaceAttribute); + INamedTypeSymbol? comObjectType = context.Compilation.GetBestTypeByMetadataName(TypeNames.System_Runtime_InteropServices_Marshalling_ComObject); + + List> sourceGeneratedComRecognizers = new(); + if (generatedComClassAttribute is not null) + { + sourceGeneratedComRecognizers.Add(type => type.GetAttributes().Any(attr => generatedComClassAttribute.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))); + } + if (generatedComInterfaceAttribute is not null) + { + sourceGeneratedComRecognizers.Add(type => type.GetAttributes().Any(attr => generatedComInterfaceAttribute.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))); + } + if (comObjectType is not null) + { + sourceGeneratedComRecognizers.Add(type => type.Equals(comObjectType, SymbolEqualityComparer.Default)); + } + + if (marshalType is null || sourceGeneratedComRecognizers.Count == 0) + { + return; + } + + var methodsOfInterest = new Dictionary>>(SymbolEqualityComparer.Default); + + var firstArgumentTypeLookup = CreateArgumentTypeLookup(0); + + var firstArgumentTypeLookupOnly = ImmutableArray.Create(firstArgumentTypeLookup); + + methodsOfInterest.Add(marshalType.GetMembers("SetComObjectData")[0], firstArgumentTypeLookupOnly); + methodsOfInterest.Add(marshalType.GetMembers("GetComObjectData")[0], firstArgumentTypeLookupOnly); + methodsOfInterest.Add(marshalType.GetMembers("ReleaseComObject")[0], firstArgumentTypeLookupOnly); + methodsOfInterest.Add(marshalType.GetMembers("FinalReleaseComObject")[0], firstArgumentTypeLookupOnly); + + foreach (var createAggregatedObject in marshalType.GetMembers("CreateAggregatedObject")) + { + if (createAggregatedObject is IMethodSymbol { IsGenericMethod: true }) + { + methodsOfInterest.Add(createAggregatedObject, ImmutableArray.Create(CreateTypeArgumentTypeLookup(0), CreateArgumentTypeLookup(1))); + } + else + { + methodsOfInterest.Add(createAggregatedObject, ImmutableArray.Create(CreateArgumentTypeLookup(1))); + } + } + + foreach (var createWrapperOfType in marshalType.GetMembers("CreateWrapperOfType")) + { + if (createWrapperOfType is IMethodSymbol { IsGenericMethod: true }) + { + methodsOfInterest.Add(createWrapperOfType, ImmutableArray.Create(CreateTypeArgumentTypeLookup(0), CreateTypeArgumentTypeLookup(1), firstArgumentTypeLookup)); + } + else + { + methodsOfInterest.Add(createWrapperOfType, ImmutableArray.Create(firstArgumentTypeLookup, CreateTypeOfArgumentTypeLookup(1))); + } + } + + methodsOfInterest.Add(marshalType.GetMembers("GetTypedObjectForIUnknown")[0], ImmutableArray.Create(CreateTypeOfArgumentTypeLookup(1))); + methodsOfInterest.Add(marshalType.GetMembers("GetIUnknownForObject")[0], firstArgumentTypeLookupOnly); + methodsOfInterest.Add(marshalType.GetMembers("GetIDispatchForObject")[0], firstArgumentTypeLookupOnly); + + foreach (var getComInterfaceForObject in marshalType.GetMembers("GetComInterfaceForObject")) + { + if (getComInterfaceForObject is IMethodSymbol { IsGenericMethod: true }) + { + methodsOfInterest.Add(getComInterfaceForObject, ImmutableArray.Create(CreateTypeArgumentTypeLookup(0), CreateTypeArgumentTypeLookup(1), firstArgumentTypeLookup)); + } + else + { + methodsOfInterest.Add(getComInterfaceForObject, ImmutableArray.Create(CreateArgumentTypeLookup(0), CreateTypeOfArgumentTypeLookup(1))); + } + } + + context.RegisterOperationAction(context => + { + var operation = (IInvocationOperation)context.Operation; + + if (methodsOfInterest.TryGetValue(operation.TargetMethod.OriginalDefinition, out ImmutableArray> discoverers)) + { + foreach (Func discoverer in discoverers) + { + var typeInfo = discoverer(operation); + if (typeInfo is (ITypeSymbol targetType, Location diagnosticLocation)) + { + foreach (var recognizer in sourceGeneratedComRecognizers) + { + if (recognizer(targetType)) + { + context.ReportDiagnostic( + Diagnostic.Create( + RuntimeComApisDoNotSupportSourceGeneratedCom, + diagnosticLocation, + operation.TargetMethod.ToMinimalDisplayString(operation.SemanticModel, operation.Syntax.SpanStart), + targetType.ToMinimalDisplayString(operation.SemanticModel, operation.Syntax.SpanStart))); + break; + } + } + } + } + } + }, OperationKind.Invocation); + + static Func CreateArgumentTypeLookup(int ordinal) => invocation => invocation.GetArgumentByOrdinal(ordinal).Value switch + { + IConversionOperation conversion => (conversion.Operand.Type, conversion.Operand.Syntax.GetLocation()), + IOperation op => (op.Type, op.Syntax.GetLocation()) + }; + + static Func CreateTypeArgumentTypeLookup(int ordinal) => invocation => + { + var type = invocation.TargetMethod.TypeArguments[ordinal]; + + var invocationSyntax = (InvocationExpressionSyntax)invocation.Syntax; + var expression = invocationSyntax.Expression; + + Location? location = null; + + if (expression.IsKind(SyntaxKind.SimpleMemberAccessExpression)) + { + expression = ((MemberAccessExpressionSyntax)expression).Name; + } + + if (expression.IsKind(SyntaxKind.GenericName)) + { + location = ((GenericNameSyntax)expression).TypeArgumentList.Arguments[ordinal].GetLocation(); + } + + if (location is null) + { + // If we couldn't find the type argument in source, then it was inferred. Don't emit a warning for the inferred type argument. + // We'll emit a warning for the argument that was passed in instead. + return null; + } + + return (type, location); + }; + + static Func CreateTypeOfArgumentTypeLookup(int ordinal) => invocation => invocation.GetArgumentByOrdinal(ordinal).Value switch + { + ITypeOfOperation typeOf => (typeOf.TypeOperand, ((TypeOfExpressionSyntax)typeOf.Syntax).Type.GetLocation()), + _ => null + }; + }); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/AttributeInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/AttributeInfo.cs index 992c286..fed18f1 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/AttributeInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/AttributeInfo.cs @@ -1,8 +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 System.Collections; -using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceContext.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceContext.cs index f8184a0..b58217a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceContext.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceContext.cs @@ -1,13 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.Interop { diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs index cdfdbfa..d0334a4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.csproj b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.csproj index a9116c3..c8d1f18 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.csproj +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.csproj @@ -18,10 +18,12 @@ - - + + + + diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs index 9faa09c..54b0864 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComMethodInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComMethodInfo.cs index c80290f..2fb9426 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComMethodInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComMethodInfo.cs @@ -1,7 +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 System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs index f8c42b2..36095b7 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs @@ -1,12 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Text; using Microsoft.CodeAnalysis; namespace Microsoft.Interop 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 f797fce..b1660ff 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx @@ -267,4 +267,52 @@ The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on interface '{0}' is invalid. {1} + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + Convert to 'GeneratedComInterface' + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + Convert to 'GeneratedComInterface' and allow unsafe code + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + \ 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 0776aec..0194951 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. Analýza požadovaná ke generování kódu pro toto rozhraní nebo metodu se nezdařila kvůli neočekávanému vzoru kódu. Pokud používáte novou nebo nekonvenční syntaxi, zvažte použití jiné syntaxe. @@ -37,6 +57,21 @@ Základnímu rozhraní COM se nepodařilo vygenerovat zdroj. ComInterfaceGenerator nevygeneruje zdroj pro toto rozhraní. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. Model COM vygenerovaný zdrojem bude ignorovat všechny nepodporované konfigurace. @@ -72,6 +107,36 @@ Zadaná konfigurace není podporována modelem COM generovaným zdrojem. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. Konfigurace „StringMarshalling“ a „StringMarshallingCustomType“ se musí shodovat se základním rozhraním COM. @@ -212,6 +277,21 @@ Zadané rozhraní je odvozeno ze dvou nebo více rozhraní s atributem GeneratedComInterfaceAttribute. + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. U typů, které nejsou podporovány modelem COM generovaným zdrojem, bude výsledný ukazatel funkce při zařazování zadaného typu spoléhat na základní modul runtime. 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 3d7ec0c..b1f1441 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. Die Analyse, die erforderlich ist, um Code für diese Schnittstelle oder Methode zu erzeugen, ist aufgrund eines unerwarteten Codemusters fehlgeschlagen. Wenn Sie eine neue oder unkonventionelle Syntax verwenden, sollten Sie eine andere Syntax verwenden. @@ -37,6 +57,21 @@ Die Basis-COM-Schnittstelle konnte die Quelle nicht generieren. ComInterfaceGenerator generiert keine Quelle für diese Schnittstelle. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. Quellgeneriertes COM ignoriert alle Konfigurationen, die nicht unterstützt werden. @@ -72,6 +107,36 @@ Die angegebene Konfiguration wird vom quellgenerierten COM nicht unterstützt. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. Die Konfiguration von "StringMarshalling" und "StringMarshallingCustomType" muss mit der COM-Basisschnittstelle übereinstimmen. @@ -212,6 +277,21 @@ Die angegebene Schnittstelle wird von mindestens zwei Schnittstellen abgeleitet, die "GeneratedComInterfaceAttribute" zugeordnet sind. + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. Bei Typen, die vom quellgenerierten COM nicht unterstützt werden, basiert der resultierende Funktionszeiger auf der zugrunde liegenden Laufzeit, um den angegebenen Typ zu marshallen. 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 a24178f..3fa88a7 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. Se ha producido un error en el análisis necesario para generar código para esta interfaz o método debido a un patrón de código inesperado. Si está usando sintaxis nueva o no convencional, considere la posibilidad de usar otra sintaxis. @@ -37,6 +57,21 @@ La interfaz COM base no pudo generar el origen. ComInterfaceGenerator no generará el origen para esta interfaz. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. COM generado por el origen omitirá cualquier configuración que no se admita. @@ -72,6 +107,36 @@ COM generado por origen no admite la configuración especificada. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. La configuración de "StringMarshalling" y "StringMarshallingCustomType" debe coincidir con la interfaz COM base. @@ -212,6 +277,21 @@ La interfaz especificada deriva de dos o más interfaces con atributos "GeneratedComInterfaceAttribute". + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. Para los tipos que no son compatibles con COM generado por el origen, el puntero de función resultante se basará en el tiempo de ejecución subyacente para serializar el tipo especificado. 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 97bdf01..e76c3db 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. L’analyse requise pour générer du code pour cette interface ou cette méthode a échoué en raison d’un modèle de code inattendu. Si vous utilisez une syntaxe nouvelle ou syntaxe correcte, utilisez une autre syntaxe. @@ -37,6 +57,21 @@ L’interface COM de base n’a pas pu générer la source. ComInterfaceGenerator ne génère pas de source pour cette interface. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. COM généré par la source ignore toute configuration qui n’est pas prise en charge. @@ -72,6 +107,36 @@ La configuration spécifiée n’est pas prise en charge par com généré par la source. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. La configuration de « StringMarshalling » et de « StringMarshallingCustomType » doit correspondre à l’interface COM de base. @@ -212,6 +277,21 @@ L’interface spécifiée dérive de deux ou plusieurs interfaces avec attribut 'GeneratedComInterfaceAttribute'. + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. Pour les types qui ne sont pas pris en charge par com généré par la source, le pointeur de fonction résultant s’appuie sur le runtime sous-jacent pour marshaler le type spécifié. 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 ae11d9f..5806cfc 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. L'analisi necessaria per generare il codice per questa interfaccia o per questo metodo non è riuscita a causa di un modello di codice imprevisto. Se si usa una sintassi nuova o non intenzionale, provare a usare un'altra sintassi. @@ -37,6 +57,21 @@ L'interfaccia COM di base non è riuscita a generare l'origine. ComInterfaceGenerator non genererà l'origine per questa interfaccia. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. I COM generati dall'origine ignoreranno qualsiasi configurazione non supportata. @@ -72,6 +107,36 @@ La configurazione specificata non è supportata dai COM generati dall'origine. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. La configurazione di 'StringMarshalling' e 'StringMarshallingCustomType' deve corrispondere all'interfaccia COM di base. @@ -212,6 +277,21 @@ L'interfaccia specificata deriva da due o più interfacce con attributi 'GeneratedComInterfaceAttribute'. + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. Per i tipi non supportati dai COM generati dall'origine, il puntatore funzione risultante si baserà sul runtime sottostante per effettuare il marshalling del tipo specificato. 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 042d3ac..8765737 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. 予期しないコード パターンのため、このインターフェイスまたはメソッドのコードを生成するために必要な分析が失敗しました。新しい構文または従来とは異なる構文を使用している場合は、他の構文の使用を検討してください。 @@ -37,6 +57,21 @@ ベース COM インターフェイスはソースを生成できませんでした。ComInterfaceGenerator は、このインターフェイスのソースを生成しません。 + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. ソース生成済みの COM は、サポートされていない構成を無視します。 @@ -72,6 +107,36 @@ 指定された構成は、ソース生成済みの COM ではサポートされていません。 + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. 'StringMarshalling' および 'StringMarshallingCustomType' の構成は、ベース COM インターフェイスと一致する必要があります。 @@ -212,6 +277,21 @@ 指定されたインターフェイスは、2 つ以上の 'GeneratedComInterfaceAttribute' 属性インターフェイスから派生しています。 + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. ソース生成済みの COM でサポートされていない型である場合、生成された関数ポインターは、基礎となるなるランタイムに依存して、指定された型をマーシャリングします。 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 a13812c..2062b2f 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. 예기치 않은 코드 패턴으로 인해 이 인터페이스 또는 메서드에 대한 코드를 생성하는 데 필요한 분석이 실패했습니다. 새 구문 또는 이례적 구문을 사용하는 경우 다른 구문을 사용하는 것이 좋습니다. @@ -37,6 +57,21 @@ 기본 COM 인터페이스에서 원본을 생성하지 못했습니다. ComInterfaceGenerator는 이 인터페이스에 대한 원본을 생성하지 않습니다. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. 소스 생성 COM은 지원되지 않는 구성을 무시합니다. @@ -72,6 +107,36 @@ 지정된 구성은 원본 생성 COM에서 지원되지 않습니다. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. 'StringMarshalling' 및 'StringMarshallingCustomType'의 구성은 기본 COM 인터페이스와 일치해야 합니다. @@ -212,6 +277,21 @@ 지정한 인터페이스는 두 개 이상의 'GeneratedComInterfaceAttribute' 특성 인터페이스에서 파생됩니다. + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. 원본 생성 COM에서 지원하지 않는 형식의 경우 결과 함수 포인터는 기본 런타임을 사용하여 지정된 형식을 마샬링합니다. 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 63f9240..62d7ce1 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. Analiza wymagana do wygenerowania kodu dla tego interfejsu lub metody nie powiodła się z powodu nieoczekiwanego wzorca kodu. Jeśli używasz nowej składni lub nieszablonowej składni, rozważ użycie innej składni. @@ -37,6 +57,21 @@ Podstawowy interfejs COM nie może wygenerować źródła. Program ComInterfaceGenerator nie wygeneruje źródła dla tego interfejsu. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. COM wygenerowany przez źródło zignoruje każdą konfigurację, która nie jest obsługiwana. @@ -72,6 +107,36 @@ Określona konfiguracja nie jest obsługiwana przez COM wygenerowany przez źródło. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. Konfiguracja elementów „StringMarssourceing” i „StringMarsxtingCustomType” musi być zgodna z podstawowym interfejsem COM. @@ -212,6 +277,21 @@ Określony interfejs pochodzi z co najmniej dwóch interfejsów z atrybutem „GeneratedComInterfaceAttribute”. + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. W przypadku typów, które nie są obsługiwane przez COM wygenerowany przez źródło, wynikowy wskaźnik funkcji będzie polegał na bazowym środowisku uruchomieniowym w celu skierowania określonego typu. 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 9ce3756..5486a45 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. A análise necessária para gerar código para essa interface ou método falhou devido a um padrão de código inesperado. Se você estiver usando sintaxe nova ou não convencional, considere usar outra sintaxe. @@ -37,6 +57,21 @@ A interface COM base falhou ao gerar a fonte. ComInterfaceGenerator não irá gerar fonte para esta interface. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. Um COM gerado pela origem ignorará qualquer configuração sem suporte. @@ -72,6 +107,36 @@ Um COM gerado pela origem não dá suporte a uma configuração especificada. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. A configuração de 'StringMarshalling' e 'StringMarshallingCustomType' deve corresponder à interface COM base. @@ -212,6 +277,21 @@ A interface especificada deriva de duas ou mais interfaces atribuídas a 'GeneratedComInterfaceAttribute'. + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. Para tipos sem suporte para um COM gerado pela origem, o ponteiro de função resultante dependerá do tempo de execução subjacente para realizar marshaling no tipo especificado. 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 01ab6e8..12e76c9 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. Произошел сбой анализа, необходимого для создания кода для этого интерфейса или метода, из-за непредвиденного шаблона кода. Если вы используйте новый или нестандартный синтаксис, попробуйте использовать другой синтаксис. @@ -37,6 +57,21 @@ Базовому COM-интерфейсу не удалось создать источник. ComInterfaceGenerator не будет создавать источник для этого интерфейса. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. Модель COM генератора исходного кода будет игнорировать любую неподдерживаемую конфигурацию. @@ -72,6 +107,36 @@ Указанная конфигурация не поддерживается моделью COM генератора исходного кода. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. Конфигурация "StringMarshalling" и "StringMarshallingCustomType" должна соответствовать базовому COM-интерфейсу. @@ -212,6 +277,21 @@ Указанный интерфейс является производным от двух или более интерфейсов с атрибутом "GeneratedComInterfaceAttribute". + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. Для типов, которые не поддерживаются моделью COM генератора исходного кода, результирующий указатель на функцию будет выполнять маршалинг указанного типа на базе используемой среды выполнения. 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 a14f019..c40fff4 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. Bu arabirim veya yöntem için kod oluşturmak için gerekli analiz beklenmeyen bir kod deseni nedeniyle başarısız oldu. Yeni veya alışılmadık bir söz dizimi kullanıyorsanız başka bir söz dizimi kullanmayı deneyin. @@ -37,6 +57,21 @@ Temel COM arabirimi kaynak oluşturamadı. ComInterfaceGenerator bu arabirim için kaynak oluşturamaz. + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. Kaynak tarafından oluşturulan COM, desteklenmeyen herhangi bir yapılandırmayı yoksayar. @@ -72,6 +107,36 @@ Belirtilen yapılandırma, kaynak tarafından oluşturulan COM tarafından desteklenmiyor. + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. 'StringMarshalling' ve 'StringMarshallingCustomType' yapılandırması temel COM arabirimiyle eşleşmelidir. @@ -212,6 +277,21 @@ Belirtilen arabirim 'GeneratedComInterfaceAttribute' özniteliğine sahip iki veya daha fazla arabirimden türetildi. + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. Kaynak tarafından oluşturulan COM tarafından desteklenmeyen türler için, ortaya çıkan işlev işaretçisi, belirtilen türü sıralamak için temeldeki çalışma zamanına güvenir. 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 5e68280..4f4d31c 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. 由于意外的代码模式,为此接口或方法生成代码所需的分析失败。如果你使用的是新语法或非常规语法,请考虑使用其他语法。 @@ -37,6 +57,21 @@ 基本 COM 接口无法生成源。ComInterfaceGenerator 不会为此接口生成源。 + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. 源生成的 COM 将忽略任何不受支持的配置。 @@ -72,6 +107,36 @@ 源生成的 COM 不支持指定的配置。 + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. "StringMarshalling" 和 "StringMarshallingCustomType" 的配置必须与基本 COM 接口匹配。 @@ -212,6 +277,21 @@ 指定的接口派生自两个或更多“GeneratedComInterfaceAttribute”特性化接口。 + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. 对于源生成的 COM 不支持的类型,生成的函数指针将依赖基础运行时来封送指定的类型。 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 e9d2af2..c47e7b9 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 @@ -2,6 +2,26 @@ + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM and allow unsafe code + + + + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + This type implements at least one type with the 'GeneratedComInterfaceAttribute' attribute. Add the 'GeneratedComClassAttribute' to enable passing this type to COM and exposing the COM interfaces for the types with the 'GeneratedComInterfaceAttribute' from objects of this type. + + + + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + Add the 'GeneratedComClassAttribute' to '{0}' to enable passing objects of type '{0}' to COM + + + + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + Add 'GeneratedComClassAttribute' to enable passing objects of this type to COM + + 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. 產生此介面或方法程式碼所需的分析失敗,因為有未預期的程式碼模式。如果您使用的是新語法或非常規語法,請考慮使用其他語法。 @@ -37,6 +57,21 @@ 基底 COM 介面無法產生來源。ComInterfaceGenerator 不會產生此介面的來源。 + + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + .NET COM hosting with 'EnableComHosting' only supports built-in COM interop. It does not support source-generated COM interop with 'GeneratedComInterfaceAttribute'. + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute'. Change any COM exposed interfaces implemented by '{0}' to use the 'System.Runtime.InteropServices.ComVisibleAttribute' instead + + + + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + .NET COM hosting with 'EnableComHosting' does not support interfaces with the 'GeneratedComInterfaceAttribute' + + Source-generated COM will ignore any configuration that is not supported. 来源產生的 COM 將會略過任何不支援的設定。 @@ -72,6 +107,36 @@ 来源產生的 COM 不支援指定的設定。 + + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + Converting this interface to use 'GeneratedComInterfaceAttribute' may produce invalid code and may require additional work + + + + Convert to 'GeneratedComInterface' and allow unsafe code + Convert to 'GeneratedComInterface' and allow unsafe code + + + + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Use 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + Converting this API to 'GeneratedComInterfaceAttribute' will require additional code to provide custom marshallers for some parameters. + + + + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + Mark the type '{0}' with 'GeneratedComInterfaceAttribute' instead of 'ComImportAttribute' to generate COM marshalling code at compile time + + + + Convert to 'GeneratedComInterface' + Convert to 'GeneratedComInterface' + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' must match the base COM interface. 'StringMarshalling' 和 'StringMarshallingCustomType' 的設定必須和基底 COM 介面相符。 @@ -212,6 +277,21 @@ 指定的介面衍生自兩個或兩個以上的 'GeneratedComInterfaceAttribute'-屬性介面。 + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM and will fail at runtime + + + + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + The method '{0}' only supports runtime-based COM interop and will not work with type '{1}' + + + + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + COM Interop APIs on 'System.Runtime.InteropServices.Marshal' do not support source-generated COM + + For types that are not supported by source-generated COM, the resulting function pointer will rely on the underlying runtime to marshal the specified type. 對於來源產生的 COM 不支援的類型,產生的函式指標將依賴基礎執行階段來封送處理指定的類型。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/ConvertToSourceGeneratedInteropFixer.cs b/src/libraries/System.Runtime.InteropServices/gen/Common/ConvertToSourceGeneratedInteropFixer.cs new file mode 100644 index 0000000..7422d08 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/ConvertToSourceGeneratedInteropFixer.cs @@ -0,0 +1,263 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Editing; + +namespace Microsoft.Interop.Analyzers +{ + public abstract class ConvertToSourceGeneratedInteropFixer : CodeFixProvider + { + public sealed override FixAllProvider GetFixAllProvider() => CustomFixAllProvider.Instance; + + protected abstract string BaseEquivalenceKey { get; } + + protected virtual IEnumerable CreateAllFixesForDiagnosticOptions(SyntaxNode node, ImmutableDictionary options) + { + // By default, we only have one fix for the options specified from the diagnostic. + yield return new ConvertToSourceGeneratedInteropFix(CreateFixForSelectedOptions(node, options), options); + } + + protected abstract Func CreateFixForSelectedOptions(SyntaxNode node, ImmutableDictionary selectedOptions); + + protected abstract string GetDiagnosticTitle(ImmutableDictionary selectedOptions); + + /// + /// A basic string-serializable option mechanism to enable the same fixer to be used for diagnostics with slightly different properties. + /// + public abstract record Option + { + private protected Option() + { + } + + public const string AllowUnsafe = nameof(AllowUnsafe); + public const string MayRequireAdditionalWork = nameof(MayRequireAdditionalWork); + + public sealed record Bool(bool Value) : Option + { + public override string ToString() => $"b:{Value};"; + } + + public sealed record String(string Value) : Option + { + public override string ToString() => $"s:{Value};"; + } + + public static ImmutableDictionary ParseOptionsFromEquivalenceKey(string equivalenceKey) + { + ImmutableDictionary.Builder options = ImmutableDictionary.CreateBuilder(); + // The first ';' separates the base equivalence key from the options + foreach (string option in equivalenceKey.Split(';').Skip(0)) + { + string[] optionKeyAndValue = option.Split('='); + if (optionKeyAndValue.Length != 2 || optionKeyAndValue[1].Length < 3) + { + continue; + } + + string type = optionKeyAndValue[1].Substring(0, 2); + string value = optionKeyAndValue[1].Substring(2); + if (type == "b:") + { + options.Add(optionKeyAndValue[0], new Bool(bool.Parse(value))); + } + else if (type == "s:") + { + options.Add(optionKeyAndValue[0], new String(value)); + } + } + + return options.ToImmutable(); + } + + public static string CreateEquivalenceKeyFromOptions(string baseEquivalenceKey, ImmutableDictionary options) + { + StringBuilder equivalenceKeyBuilder = new(baseEquivalenceKey); + foreach (var option in options.OrderBy(item => item.Key)) + { + equivalenceKeyBuilder.Append($";{option.Key}={option.Value}"); + } + return equivalenceKeyBuilder.ToString(); + } + } + + protected abstract ImmutableDictionary ParseOptionsFromDiagnostic(Diagnostic diagnostic); + + private static async Task ApplyActionAndEnableUnsafe(Solution solution, DocumentId documentId, Func documentBasedFix, CancellationToken ct) + { + var editor = new SolutionEditor(solution); + var docEditor = await editor.GetDocumentEditorAsync(documentId, ct).ConfigureAwait(false); + await documentBasedFix(docEditor, ct).ConfigureAwait(false); + + var docProjectId = documentId.ProjectId; + var updatedSolution = editor.GetChangedSolution(); + return AddUnsafe(updatedSolution, updatedSolution.GetProject(docProjectId)); + } + + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + // Get the syntax root and semantic model + Document doc = context.Document; + SyntaxNode? root = await doc.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root == null) + return; + + SyntaxNode node = root.FindNode(context.Span); + + bool enableUnsafe = doc.Project.CompilationOptions is CSharpCompilationOptions { AllowUnsafe: false }; + foreach (Diagnostic diagnostic in context.Diagnostics) + { + var options = ParseOptionsFromDiagnostic(diagnostic); + foreach (var fix in CreateAllFixesForDiagnosticOptions(node, options)) + { + if (enableUnsafe) + { + var selectedOptions = fix.SelectedOptions.Add(Option.AllowUnsafe, new Option.Bool(true)); + + context.RegisterCodeFix( + CodeAction.Create( + GetDiagnosticTitle(selectedOptions), + ct => ApplyActionAndEnableUnsafe(doc.Project.Solution, doc.Id, fix.ApplyFix, ct), + Option.CreateEquivalenceKeyFromOptions(BaseEquivalenceKey, selectedOptions)), + diagnostic); + } + else + { + context.RegisterCodeFix( + CodeAction.Create( + GetDiagnosticTitle(fix.SelectedOptions), + async ct => + { + DocumentEditor editor = await DocumentEditor.CreateAsync(doc, ct).ConfigureAwait(false); + + await fix.ApplyFix(editor, ct).ConfigureAwait(false); + + return editor.GetChangedDocument(); + }, + Option.CreateEquivalenceKeyFromOptions(BaseEquivalenceKey, fix.SelectedOptions)), + diagnostic); + } + } + } + } + + protected record struct ConvertToSourceGeneratedInteropFix(Func ApplyFix, ImmutableDictionary SelectedOptions); + + private sealed class CustomFixAllProvider : FixAllProvider + { + public static readonly CustomFixAllProvider Instance = new(); + public override async Task GetFixAsync(FixAllContext fixAllContext) + { + var options = Option.ParseOptionsFromEquivalenceKey(fixAllContext.CodeActionEquivalenceKey); + var codeFixProvider = (ConvertToSourceGeneratedInteropFixer)fixAllContext.CodeFixProvider; + + bool addUnsafe = options.TryGetValue(Option.AllowUnsafe, out Option allowUnsafeOption) && allowUnsafeOption is Option.Bool(true); + + bool includeFixesWithAdditionalWork = options.TryGetValue(Option.MayRequireAdditionalWork, out Option includeFixesWithAdditionalWorkOption) && includeFixesWithAdditionalWorkOption is Option.Bool(true); + ImmutableArray diagnosticsInScope = await fixAllContext.GetDiagnosticsInScopeAsync().ConfigureAwait(false); + + + return CodeAction.Create(codeFixProvider.GetDiagnosticTitle(options), + async ct => + { + HashSet projectsToAddUnsafe = new(); + SolutionEditor solutionEditor = new SolutionEditor(fixAllContext.Solution); + + foreach (var diagnostic in diagnosticsInScope) + { + bool mayRequireAdditionalWork = diagnostic.Properties.TryGetValue(Option.MayRequireAdditionalWork, out string mayRequireAdditionalWorkString) + && bool.TryParse(mayRequireAdditionalWorkString, out bool mayRequireAdditionalWorkValue) + ? mayRequireAdditionalWorkValue + : false; + if (mayRequireAdditionalWork && !includeFixesWithAdditionalWork) + { + // Don't fix any diagnostics that require additional work if the "fix all" command wasn't triggered from a location + // that was able to warn the user that additional work may be required. + continue; + } + DocumentId documentId = solutionEditor.OriginalSolution.GetDocumentId(diagnostic.Location.SourceTree)!; + DocumentEditor editor = await solutionEditor.GetDocumentEditorAsync(documentId, ct).ConfigureAwait(false); + SyntaxNode root = await diagnostic.Location.SourceTree.GetRootAsync(ct).ConfigureAwait(false); + + SyntaxNode node = root.FindNode(diagnostic.Location.SourceSpan); + + var documentBasedFix = codeFixProvider.CreateFixForSelectedOptions(node, options); + + await documentBasedFix(editor, ct).ConfigureAwait(false); + + // Record this project as a project we need to allow unsafe blocks in. + projectsToAddUnsafe.Add(solutionEditor.OriginalSolution.GetDocument(documentId).Project); + } + + Solution solutionWithUpdatedSources = solutionEditor.GetChangedSolution(); + + if (addUnsafe) + { + foreach (var project in projectsToAddUnsafe) + { + solutionWithUpdatedSources = AddUnsafe(solutionWithUpdatedSources, project); + } + } + return solutionWithUpdatedSources; + }, + equivalenceKey: fixAllContext.CodeActionEquivalenceKey); + } + } + + private static Solution AddUnsafe(Solution solution, Project project) + { + return solution.WithProjectCompilationOptions(project.Id, ((CSharpCompilationOptions)project.CompilationOptions).WithAllowUnsafe(true)); + } + + protected static void MakeNodeParentsPartial(DocumentEditor editor, SyntaxNode syntax) + { + for (SyntaxNode? node = syntax.Parent; node is not null; node = node.Parent) + { + editor.ReplaceNode(node, (node, gen) => gen.WithModifiers(node, gen.GetModifiers(node).WithPartial(true))); + } + } + + protected static SyntaxNode AddExplicitDefaultBoolMarshalling(SyntaxGenerator generator, IMethodSymbol methodSymbol, SyntaxNode generatedDeclaration, string unmanagedTypeMemberIdentifier) + { + foreach (IParameterSymbol parameter in methodSymbol.Parameters) + { + if (parameter.Type.SpecialType == SpecialType.System_Boolean + && !parameter.GetAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) + { + SyntaxNode generatedParameterSyntax = generator.GetParameters(generatedDeclaration)[parameter.Ordinal]; + generatedDeclaration = generator.ReplaceNode(generatedDeclaration, generatedParameterSyntax, generator.AddAttributes(generatedParameterSyntax, + GenerateMarshalAsUnmanagedTypeBoolAttribute(generator, unmanagedTypeMemberIdentifier))); + } + } + + if (methodSymbol.ReturnType.SpecialType == SpecialType.System_Boolean + && !methodSymbol.GetReturnTypeAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) + { + generatedDeclaration = generator.AddReturnAttributes(generatedDeclaration, + GenerateMarshalAsUnmanagedTypeBoolAttribute(generator, unmanagedTypeMemberIdentifier)); + } + + return generatedDeclaration; + + + static SyntaxNode GenerateMarshalAsUnmanagedTypeBoolAttribute(SyntaxGenerator generator, string unmanagedTypeMemberIdentifier) + => generator.Attribute(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute, + generator.AttributeArgument( + generator.MemberAccessExpression( + generator.DottedName(TypeNames.System_Runtime_InteropServices_UnmanagedType), + generator.IdentifierName(unmanagedTypeMemberIdentifier)))); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/FixAllContextExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Common/FixAllContextExtensions.cs similarity index 99% rename from src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/FixAllContextExtensions.cs rename to src/libraries/System.Runtime.InteropServices/gen/Common/FixAllContextExtensions.cs index b41ab48..c46a604 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/FixAllContextExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/FixAllContextExtensions.cs @@ -1,11 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/OperationExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Common/OperationExtensions.cs similarity index 96% rename from src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/OperationExtensions.cs rename to src/libraries/System.Runtime.InteropServices/gen/Common/OperationExtensions.cs index 6210273..0d5f5f6 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/OperationExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/OperationExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; -using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportFixer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportFixer.cs index 14cbd22..60d6796 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportFixer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportFixer.cs @@ -23,249 +23,137 @@ using static Microsoft.Interop.Analyzers.AnalyzerDiagnostics; namespace Microsoft.Interop.Analyzers { [ExportCodeFixProvider(LanguageNames.CSharp), Shared] - public sealed class ConvertToLibraryImportFixer : CodeFixProvider + public sealed class ConvertToLibraryImportFixer : ConvertToSourceGeneratedInteropFixer { - public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(Ids.ConvertToLibraryImport); - - public override FixAllProvider GetFixAllProvider() => CustomFixAllProvider.Instance; - - private const string ConvertToLibraryImportKey = "ConvertToLibraryImport,"; - private static string AppendSuffix(string entryPoint, char? entryPointSuffix) - => entryPointSuffix.HasValue && entryPoint.LastOrDefault() == entryPointSuffix.Value - ? entryPoint - : entryPoint + entryPointSuffix; - private static string AddSuffixKey(string baseKey, char suffix) => $"{baseKey}{suffix},"; - private static string AddUnsafeKey(string baseKey) => baseKey + "AddUnsafe,"; - private static string AddMayRequireAdditionalWorkKey(string baseKey) => baseKey + $"{ConvertToLibraryImportAnalyzer.MayRequireAdditionalWork},"; - - private static readonly string[] s_preferredAttributeArgumentOrder = - { - nameof(DllImportAttribute.EntryPoint), - nameof(DllImportAttribute.BestFitMapping), - nameof(DllImportAttribute.CallingConvention), - nameof(DllImportAttribute.CharSet), - nameof(DllImportAttribute.ExactSpelling), - nameof(DllImportAttribute.PreserveSig), - nameof(DllImportAttribute.SetLastError), - nameof(StringMarshalling), - nameof(DllImportAttribute.ThrowOnUnmappableChar) - }; - - public override async Task RegisterCodeFixesAsync(CodeFixContext context) - { - // Get the syntax root and semantic model - Document doc = context.Document; - SyntaxNode? root = await doc.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - if (root == null) - return; - - // Get the syntax node tied to the diagnostic and check that it is a method declaration - if (root.FindNode(context.Span) is not MethodDeclarationSyntax methodSyntax) - return; + private const string CharSetOption = nameof(CharSetOption); - bool enableUnsafe = doc.Project.CompilationOptions is CSharpCompilationOptions { AllowUnsafe: false }; + public const string SelectedSuffixOption = nameof(SelectedSuffixOption); - ICodeActionFactory codeActionFactory = enableUnsafe ? new AddUnsafeCodeActionFactory() : new DefaultCodeActionFactory(); - - foreach (Diagnostic diagnostic in context.Diagnostics) - { - bool mayRequireAdditionalWork = bool.TryParse(diagnostic.Properties[ConvertToLibraryImportAnalyzer.MayRequireAdditionalWork], out bool mayRequireAdditionalWorkValue) - ? mayRequireAdditionalWorkValue - : false; - // Register code fix - context.RegisterCodeFix( - codeActionFactory.CreateConvertToLibraryImportCodeFix(doc, methodSyntax, mayRequireAdditionalWork), - context.Diagnostics); - if (!bool.Parse(diagnostic.Properties[ConvertToLibraryImportAnalyzer.ExactSpelling])) - { - CharSet charSet = (CharSet)Enum.Parse(typeof(CharSet), diagnostic.Properties[ConvertToLibraryImportAnalyzer.CharSet]!); - // CharSet.Auto traditionally maps to either an A or W suffix - // depending on the default CharSet of the platform. - // We will offer both suffix options when CharSet.Auto is provided - // to enable developers to pick which variant they mean (since they could explicitly decide they want one or the other) - if (charSet is CharSet.None or CharSet.Ansi or CharSet.Auto) - { - context.RegisterCodeFix( - codeActionFactory.CreateConvertToLibraryImportWithSuffixCodeFix(doc, methodSyntax, 'A', mayRequireAdditionalWork), - context.Diagnostics); - } - if (charSet is CharSet.Unicode or CharSet.Auto) - { - context.RegisterCodeFix( - codeActionFactory.CreateConvertToLibraryImportWithSuffixCodeFix(doc, methodSyntax, 'W', mayRequireAdditionalWork), - context.Diagnostics); - } - } - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(Ids.ConvertToLibraryImport); - internal interface ICodeActionFactory - { - CodeAction CreateConvertToLibraryImportCodeFix(Document document, MethodDeclarationSyntax methodSyntax, bool mayRequireAdditionalWork); - CodeAction CreateConvertToLibraryImportWithSuffixCodeFix(Document document, MethodDeclarationSyntax methodSyntax, char suffix, bool mayRequireAdditionalWork); - } + protected override string BaseEquivalenceKey => "ConvertToLibraryImport"; - private sealed class DefaultCodeActionFactory : ICodeActionFactory + protected override string GetDiagnosticTitle(ImmutableDictionary selectedOptions) { - public CodeAction CreateConvertToLibraryImportCodeFix(Document document, MethodDeclarationSyntax methodSyntax, bool mayRequireAdditionalWork) + bool allowUnsafe = selectedOptions.TryGetValue(Option.AllowUnsafe, out Option? allowUnsafeOption) && allowUnsafeOption is Option.Bool(true); + string? suffix = null; + bool hasSuffix = false; + if (selectedOptions.TryGetValue(SelectedSuffixOption, out Option? suffixOption) && suffixOption is Option.String(string suffixValue)) { - return CodeAction.Create( - SR.ConvertToLibraryImport, - cancelToken => ConvertToLibraryImport( - document, - methodSyntax, - mayRequireAdditionalWork, - entryPointSuffix: null, - cancelToken), - equivalenceKey: mayRequireAdditionalWork ? AddMayRequireAdditionalWorkKey(ConvertToLibraryImportKey) : ConvertToLibraryImportKey); + hasSuffix = true; + suffix = suffixValue; } - - public CodeAction CreateConvertToLibraryImportWithSuffixCodeFix(Document document, MethodDeclarationSyntax methodSyntax, char suffix, bool mayRequireAdditionalWork) + return (allowUnsafe, hasSuffix) switch { - return CodeAction.Create( - SR.Format(SR.ConvertToLibraryImportWithSuffix, suffix), - cancelToken => ConvertToLibraryImport( - document, - methodSyntax, - mayRequireAdditionalWork, - entryPointSuffix: suffix, - cancelToken), - equivalenceKey: AddSuffixKey(mayRequireAdditionalWork ? AddMayRequireAdditionalWorkKey(ConvertToLibraryImportKey) : ConvertToLibraryImportKey, suffix)); - } + (true, true) => SR.Format(SR.ConvertToLibraryImportWithSuffixAddUnsafe, suffix), + (true, false) => SR.ConvertToLibraryImportAddUnsafe, + (false, true) => SR.Format(SR.ConvertToLibraryImportWithSuffix, suffix), + (false, false) => SR.ConvertToLibraryImport + }; } - private sealed class AddUnsafeCodeActionFactory : ICodeActionFactory + protected override ImmutableDictionary ParseOptionsFromDiagnostic(Diagnostic diagnostic) { - public CodeAction CreateConvertToLibraryImportCodeFix(Document document, MethodDeclarationSyntax methodSyntax, bool mayRequireAdditionalWork) + var optionsBuilder = ImmutableDictionary.CreateBuilder(); + // Only add the "May require additional work" option if it is true. This simplifies our equivalence key and makes testing easier. + if (diagnostic.Properties.TryGetValue(ConvertToLibraryImportAnalyzer.MayRequireAdditionalWork, out string? mayRequireAdditionalWork) && bool.Parse(mayRequireAdditionalWork)) { - return CodeAction.Create( - SR.ConvertToLibraryImportAddUnsafe, - async cancelToken => - { - Solution solutionWithUnsafe = AddUnsafe(document.Project.Solution, document.Project); - SolutionEditor editor = new SolutionEditor(solutionWithUnsafe); - - await ConvertToLibraryImport( - await editor.GetDocumentEditorAsync(document.Id, cancelToken).ConfigureAwait(false), - methodSyntax, - mayRequireAdditionalWork, - entryPointSuffix: null, - cancelToken).ConfigureAwait(false); - return editor.GetChangedSolution(); - }, - equivalenceKey: AddUnsafeKey(mayRequireAdditionalWork ? AddMayRequireAdditionalWorkKey(ConvertToLibraryImportKey) : ConvertToLibraryImportKey)); + optionsBuilder.Add(Option.MayRequireAdditionalWork, new Option.Bool(true)); } - - public CodeAction CreateConvertToLibraryImportWithSuffixCodeFix(Document document, MethodDeclarationSyntax methodSyntax, char suffix, bool mayRequireAdditionalWork) + if (!bool.Parse(diagnostic.Properties[ConvertToLibraryImportAnalyzer.ExactSpelling])) { - return CodeAction.Create( - SR.Format(SR.ConvertToLibraryImportWithSuffixAddUnsafe, suffix), - async cancelToken => - { - Solution solutionWithUnsafe = AddUnsafe(document.Project.Solution, document.Project); - SolutionEditor editor = new SolutionEditor(solutionWithUnsafe); - - await ConvertToLibraryImport( - await editor.GetDocumentEditorAsync(document.Id, cancelToken).ConfigureAwait(false), - methodSyntax, - mayRequireAdditionalWork, - entryPointSuffix: suffix, - cancelToken).ConfigureAwait(false); - return editor.GetChangedSolution(); - }, - equivalenceKey: AddUnsafeKey(AddSuffixKey(mayRequireAdditionalWork ? AddMayRequireAdditionalWorkKey(ConvertToLibraryImportKey) : ConvertToLibraryImportKey, suffix))); + optionsBuilder.Add(CharSetOption, new Option.String(diagnostic.Properties[ConvertToLibraryImportAnalyzer.CharSet])); } + return optionsBuilder.ToImmutable(); } - private sealed class CustomFixAllProvider : FixAllProvider + protected override IEnumerable CreateAllFixesForDiagnosticOptions(SyntaxNode node, ImmutableDictionary options) { - public static readonly CustomFixAllProvider Instance = new(); - public override async Task GetFixAsync(FixAllContext fixAllContext) - { - bool addUnsafe = fixAllContext.CodeActionEquivalenceKey.Contains(",AddUnsafe,"); - bool includeFixesWithAdditionalWork = fixAllContext.CodeActionEquivalenceKey.Contains($",{ConvertToLibraryImportAnalyzer.MayRequireAdditionalWork},"); - ImmutableArray diagnosticsInScope = await fixAllContext.GetDiagnosticsInScopeAsync().ConfigureAwait(false); + bool warnForAdditionalWork = options.TryGetValue(Option.MayRequireAdditionalWork, out Option mayRequireAdditionalWork) && mayRequireAdditionalWork is Option.Bool(true); - return CodeAction.Create(addUnsafe ? SR.ConvertToLibraryImportAddUnsafe : SR.ConvertToLibraryImport, - async ct => - { - HashSet projectsToAddUnsafe = new(); - SolutionEditor solutionEditor = new SolutionEditor(fixAllContext.Solution); + CharSet? charSet = options.TryGetValue(CharSetOption, out Option charSetOption) && charSetOption is Option.String(string charSetString) && Enum.TryParse(charSetString, out CharSet result) ? result : null; - foreach (var diagnostic in diagnosticsInScope) - { - bool mayRequireAdditionalWork = bool.TryParse(diagnostic.Properties[ConvertToLibraryImportAnalyzer.MayRequireAdditionalWork], out bool mayRequireAdditionalWorkValue) - ? mayRequireAdditionalWorkValue - : false; - if (mayRequireAdditionalWork && !includeFixesWithAdditionalWork) - { - // Don't fix any diagnostics that require additional work if the "fix all" command wasn't triggered from a location - // that was able to warn the user that additional work may be required. - continue; - } - DocumentId documentId = solutionEditor.OriginalSolution.GetDocumentId(diagnostic.Location.SourceTree)!; - DocumentEditor editor = await solutionEditor.GetDocumentEditorAsync(documentId, ct).ConfigureAwait(false); - SyntaxNode root = await diagnostic.Location.SourceTree.GetRootAsync(ct).ConfigureAwait(false); - - // Get the syntax node tied to the diagnostic and check that it is a method declaration - if (root.FindNode(diagnostic.Location.SourceSpan) is not MethodDeclarationSyntax methodSyntax) - continue; - - await ConvertToLibraryImport(editor, methodSyntax, mayRequireAdditionalWork, GetSuffixFromEquivalenceKey(fixAllContext.CodeActionEquivalenceKey), ct).ConfigureAwait(false); - - // Record this project as a project we need to allow unsafe blocks in. - projectsToAddUnsafe.Add(solutionEditor.OriginalSolution.GetDocument(documentId).Project); - } - - Solution solutionWithUpdatedSources = solutionEditor.GetChangedSolution(); - - if (addUnsafe) - { - foreach (var project in projectsToAddUnsafe) - { - solutionWithUpdatedSources = AddUnsafe(solutionWithUpdatedSources, project); - } - } - return solutionWithUpdatedSources; - }, - equivalenceKey: fixAllContext.CodeActionEquivalenceKey); - } + // We don't want the CharSet option contributing to the "selected options" set for the fix, so we remove it here. + var selectedOptions = options.Remove(CharSetOption); + yield return new ConvertToSourceGeneratedInteropFix( + (editor, ct) => + ConvertToLibraryImport( + editor, + node, + warnForAdditionalWork, + null, + ct), + selectedOptions); - private static char? GetSuffixFromEquivalenceKey(string equivalenceKey) + if (charSet is not null) { - if (equivalenceKey.Contains(",A,")) + + // CharSet.Auto traditionally maps to either an A or W suffix + // depending on the default CharSet of the platform. + // We will offer both suffix options when CharSet.Auto is provided + // to enable developers to pick which variant they mean (since they could explicitly decide they want one or the other) + if (charSet is CharSet.None or CharSet.Ansi or CharSet.Auto) { - return 'A'; + yield return new ConvertToSourceGeneratedInteropFix( + (editor, ct) => + ConvertToLibraryImport( + editor, + node, + warnForAdditionalWork, + 'A', + ct), + selectedOptions.Add(SelectedSuffixOption, new Option.String("A"))); } - if (equivalenceKey.Contains(",W,")) + if (charSet is CharSet.Unicode or CharSet.Auto) { - return 'W'; + yield return new ConvertToSourceGeneratedInteropFix( + (editor, ct) => + ConvertToLibraryImport( + editor, + node, + warnForAdditionalWork, + 'W', + ct), + selectedOptions.Add(SelectedSuffixOption, new Option.String("W"))); } - return null; } } - private static Solution AddUnsafe(Solution solution, Project project) + protected override Func CreateFixForSelectedOptions(SyntaxNode node, ImmutableDictionary selectedOptions) { - return solution.WithProjectCompilationOptions(project.Id, ((CSharpCompilationOptions)project.CompilationOptions).WithAllowUnsafe(true)); + bool warnForAdditionalWork = selectedOptions.TryGetValue(Option.MayRequireAdditionalWork, out Option mayRequireAdditionalWork) && mayRequireAdditionalWork is Option.Bool(true); + char? suffix = selectedOptions.TryGetValue(SelectedSuffixOption, out Option selectedSuffixOption) && selectedSuffixOption is Option.String(string selectedSuffix) ? selectedSuffix[0] : null; + return (editor, ct) => + ConvertToLibraryImport( + editor, + node, + warnForAdditionalWork, + suffix, + ct); } - private static async Task ConvertToLibraryImport( - Document doc, - MethodDeclarationSyntax methodSyntax, - bool warnForAdditionalWork, - char? entryPointSuffix, - CancellationToken cancellationToken) - { - DocumentEditor editor = await DocumentEditor.CreateAsync(doc, cancellationToken).ConfigureAwait(false); - await ConvertToLibraryImport(editor, methodSyntax, warnForAdditionalWork, entryPointSuffix, cancellationToken).ConfigureAwait(false); - return editor.GetChangedDocument(); - } + private static string AppendSuffix(string entryPoint, char? entryPointSuffix) + => entryPointSuffix.HasValue && entryPoint.LastOrDefault() == entryPointSuffix.Value + ? entryPoint + : entryPoint + entryPointSuffix; + + private static readonly string[] s_preferredAttributeArgumentOrder = + { + nameof(DllImportAttribute.EntryPoint), + nameof(DllImportAttribute.BestFitMapping), + nameof(DllImportAttribute.CallingConvention), + nameof(DllImportAttribute.CharSet), + nameof(DllImportAttribute.ExactSpelling), + nameof(DllImportAttribute.PreserveSig), + nameof(DllImportAttribute.SetLastError), + nameof(StringMarshalling), + nameof(DllImportAttribute.ThrowOnUnmappableChar) + }; private static async Task ConvertToLibraryImport( DocumentEditor editor, - MethodDeclarationSyntax methodSyntax, + SyntaxNode methodSyntax, bool warnForAdditionalWork, char? entryPointSuffix, CancellationToken cancellationToken) @@ -296,11 +184,11 @@ namespace Microsoft.Interop.Analyzers // Replace the original method with the updated one editor.ReplaceNode(methodSyntax, generatedDeclaration); - MakeEnclosingTypesPartial(editor, methodSyntax); + MakeNodeParentsPartial(editor, methodSyntax); } private static async Task ConvertMethodDeclarationToLibraryImport( - MethodDeclarationSyntax methodSyntax, + SyntaxNode methodSyntax, DocumentEditor editor, SyntaxGenerator generator, IMethodSymbol methodSymbol, @@ -308,12 +196,12 @@ namespace Microsoft.Interop.Analyzers char? entryPointSuffix, CancellationToken cancellationToken) { - INamedTypeSymbol? dllImportAttrType = editor.SemanticModel.Compilation.GetTypeByMetadataName(typeof(DllImportAttribute).FullName); + INamedTypeSymbol? dllImportAttrType = editor.SemanticModel.Compilation.GetBestTypeByMetadataName(typeof(DllImportAttribute).FullName); if (dllImportAttrType == null) return methodSyntax; // We wouldn't have offered this code fix if the LibraryImport type isn't available, so we can be sure it isn't null here. - INamedTypeSymbol libraryImportAttrType = editor.SemanticModel.Compilation.GetTypeByMetadataName(TypeNames.LibraryImportAttribute)!; + INamedTypeSymbol libraryImportAttrType = editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.LibraryImportAttribute)!; // Make sure the method has the DllImportAttribute if (!TryGetAttribute(methodSymbol, dllImportAttrType, out AttributeData? dllImportAttr)) @@ -369,43 +257,11 @@ namespace Microsoft.Interop.Analyzers .WithIsExtern(false) .WithPartial(true)); - foreach (IParameterSymbol parameter in methodSymbol.Parameters) - { - if (parameter.Type.SpecialType == SpecialType.System_Boolean - && !parameter.GetAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) - { - MethodDeclarationSyntax generatedDeclarationSyntax = (MethodDeclarationSyntax)generatedDeclaration; - ParameterSyntax generatedParameterSyntax = generatedDeclarationSyntax.ParameterList.Parameters[parameter.Ordinal]; - generatedDeclaration = generator.ReplaceNode(generatedDeclaration, generatedParameterSyntax, generator.AddAttributes(generatedParameterSyntax, - GenerateMarshalAsUnmanagedTypeBoolAttribute(generator))); - } - } - - if (methodSymbol.ReturnType.SpecialType == SpecialType.System_Boolean - && !methodSymbol.GetReturnTypeAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) - { - generatedDeclaration = generator.AddReturnAttributes(generatedDeclaration, - GenerateMarshalAsUnmanagedTypeBoolAttribute(generator)); - } + generatedDeclaration = AddExplicitDefaultBoolMarshalling(generator, methodSymbol, generatedDeclaration, "Bool"); return generatedDeclaration; } - private static SyntaxNode GenerateMarshalAsUnmanagedTypeBoolAttribute(SyntaxGenerator generator) - => generator.Attribute(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute, - generator.AttributeArgument( - generator.MemberAccessExpression( - generator.DottedName(TypeNames.System_Runtime_InteropServices_UnmanagedType), - generator.IdentifierName("Bool")))); - - private static void MakeEnclosingTypesPartial(DocumentEditor editor, MethodDeclarationSyntax method) - { - for (TypeDeclarationSyntax? typeDecl = method.FirstAncestorOrSelf(); typeDecl is not null; typeDecl = typeDecl.Parent.FirstAncestorOrSelf()) - { - editor.ReplaceNode(typeDecl, (node, generator) => generator.WithModifiers(node, generator.GetModifiers(node).WithPartial(true))); - } - } - private static async Task TransformCallersOfNoPreserveSigMethod(DocumentEditor editor, IMethodSymbol methodSymbol, CancellationToken cancellationToken) { Document? document = editor.OriginalDocument; @@ -539,7 +395,7 @@ namespace Microsoft.Interop.Analyzers return generator.InvocationExpression( generator.MemberAccessExpression( generator.NameExpression( - editor.SemanticModel.Compilation.GetTypeByMetadataName( + editor.SemanticModel.Compilation.GetBestTypeByMetadataName( TypeNames.System_Runtime_InteropServices_Marshal)), "ThrowExceptionForHR"), node); @@ -710,7 +566,7 @@ namespace Microsoft.Interop.Analyzers CallingConvention callingConvention, out SyntaxNode? unmanagedCallConvAttribute) { - if (editor.SemanticModel.Compilation.GetTypeByMetadataName(TypeNames.UnmanagedCallConvAttribute) is null) + if (editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.UnmanagedCallConvAttribute) is null) { unmanagedCallConvAttribute = null; return false; @@ -727,13 +583,13 @@ namespace Microsoft.Interop.Analyzers ITypeSymbol? callingConventionType = callingConvention switch { CallingConvention.Cdecl => editor.SemanticModel.Compilation.ObjectType.ContainingAssembly. - GetTypeByMetadataName($"System.Runtime.CompilerServices.CallConvCdecl"), + GetTypeByMetadataName($"System.Runtime.CompilerServices.CallConvCdecl"), CallingConvention.StdCall => editor.SemanticModel.Compilation.ObjectType.ContainingAssembly. - GetTypeByMetadataName($"System.Runtime.CompilerServices.CallConvStdcall"), + GetTypeByMetadataName($"System.Runtime.CompilerServices.CallConvStdcall"), CallingConvention.ThisCall => editor.SemanticModel.Compilation.ObjectType.ContainingAssembly. - GetTypeByMetadataName($"System.Runtime.CompilerServices.CallConvThiscall"), + GetTypeByMetadataName($"System.Runtime.CompilerServices.CallConvThiscall"), CallingConvention.FastCall => editor.SemanticModel.Compilation.ObjectType.ContainingAssembly. - GetTypeByMetadataName($"System.Runtime.CompilerServices.CallConvFastcall"), + GetTypeByMetadataName($"System.Runtime.CompilerServices.CallConvFastcall"), _ => null }; @@ -749,7 +605,7 @@ namespace Microsoft.Interop.Analyzers unmanagedCallConvAttribute = generator.Attribute(TypeNames.UnmanagedCallConvAttribute, generator.AttributeArgument("CallConvs", generator.ArrayCreationExpression( - generator.TypeExpression(editor.SemanticModel.Compilation.GetTypeByMetadataName(TypeNames.System_Type)), + generator.TypeExpression(editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.System_Type)), new[] { generator.TypeOfExpression(generator.TypeExpression(callingConventionType)) }))); return true; diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj index 26ac96b..621caea 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj @@ -23,10 +23,10 @@ - - - + + + 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 de83283..75c56f3 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 @@ -36,6 +36,7 @@ namespace Microsoft.Interop public const string UnmanagedCallersOnlyAttribute = "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute"; public const string System_Runtime_InteropServices_ComImportAttribute = "System.Runtime.InteropServices.ComImportAttribute"; + public const string System_Runtime_InteropServices_ComVisibleAttribute = "System.Runtime.InteropServices.ComVisibleAttribute"; public const string VirtualMethodIndexAttribute = "System.Runtime.InteropServices.Marshalling.VirtualMethodIndexAttribute"; public const string VirtualMethodIndexAttribute_ShortName = "VirtualMethodIndexAttribute"; @@ -116,7 +117,7 @@ namespace Microsoft.Interop public const string InterfaceTypeAttribute = "System.Runtime.InteropServices.InterfaceTypeAttribute"; - public const string ComInterfaceTypeAttribute = "System.Runtime.InteropServices.ComInterfaceType"; + public const string ComInterfaceType = "System.Runtime.InteropServices.ComInterfaceType"; public const string System_Runtime_InteropServices_GuidAttribute = "System.Runtime.InteropServices.GuidAttribute"; @@ -149,5 +150,7 @@ namespace Microsoft.Interop public const string System_Runtime_InteropServices_Marshalling_SafeHandleMarshaller_Metadata = "System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller`1"; public const string System_Runtime_InteropServices_Marshalling_ComInterfaceMarshaller_Metadata = "System.Runtime.InteropServices.Marshalling.ComInterfaceMarshaller`1"; + + public const string System_Runtime_InteropServices_Marshalling_ComObject = "System.Runtime.InteropServices.Marshalling.ComObject"; } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/AddGeneratedComClassTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/AddGeneratedComClassTests.cs new file mode 100644 index 0000000..111ff15 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/AddGeneratedComClassTests.cs @@ -0,0 +1,125 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.Tasks; +using Xunit; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< + Microsoft.Interop.Analyzers.AddGeneratedComClassAnalyzer, + Microsoft.Interop.Analyzers.AddGeneratedComClassFixer>; + +namespace ComInterfaceGenerator.Unit.Tests +{ + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] + public class AddGeneratedComClassTests + { + [Fact] + public async Task TypeThatImplementsGeneratedComInterfaceType_ReportsDiagnostic() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public partial interface I + { + } + + class [|C|] : I + { + } + """; + + string fixedSource = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public partial interface I + { + } + + [GeneratedComClass] + partial class C : I + { + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, fixedSource); + } + + [Fact] + public async Task TypeThatDoesNotImplementGeneratedComInterfaceType_DoesNotReportDiagnostic() + { + string source = """ + using System.Runtime.InteropServices; + + [ComImport] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + public interface NonComInterface + { + } + + class C : I + { + } + + class D : NonComInterface + { + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Fact] + public async Task TypeThatImplementsGeneratedComInterfaceTypeTranstively_ReportsDiagnostic() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public partial interface I + { + } + + public interface J : I + { + } + + class [|C|] : J + { + } + """; + + string fixedSource = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public partial interface I + { + } + + public interface J : I + { + } + + [GeneratedComClass] + partial class C : J + { + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, fixedSource); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComHostingDoesNotSupportGeneratedComInterfaceTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComHostingDoesNotSupportGeneratedComInterfaceTests.cs new file mode 100644 index 0000000..4256d36 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComHostingDoesNotSupportGeneratedComInterfaceTests.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.Threading.Tasks; +using Xunit; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpAnalyzerVerifier< + Microsoft.Interop.Analyzers.ComHostingDoesNotSupportGeneratedComInterfaceAnalyzer>; + +namespace ComInterfaceGenerator.Unit.Tests +{ + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] + public class ComHostingDoesNotSupportGeneratedComInterfaceTests + { + [InlineData(true)] + [InlineData(false)] + [Theory] + public async Task ComVisibleType_ComImportInterfacesOnly_DoesNotReportDiagnostic(bool enableComHosting) + { + string source = """ + using System.Runtime.InteropServices; + + [ComVisible(true)] + [Guid("12D46FF1-E21A-45E4-8407-0573B30962FE")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface I + { + } + + [ComVisible(true)] + public class C : I + { + } + + """; + + await VerifyAnalyzerAsync(source, enableComHosting); + } + + [Fact] + public async Task ComVisibleType_GeneratedComInterface_NoHosting_DoesNotReportDiagnostic() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface I + { + } + + [ComVisible(true)] + public class C : I + { + } + + """; + + await VerifyAnalyzerAsync(source, enableComHosting: false); + } + + [Fact] + public async Task ComVisibleType_GeneratedComInterface_EnabledHosting_ReportsDiagnostic() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface I + { + } + + [ComVisible(true)] + public class [|C|] : I + { + } + + """; + + await VerifyAnalyzerAsync(source, enableComHosting: true); + } + + [Fact] + public async Task ComVisibleType_GeneratedComInterface_TransitiveInterface_EnabledHosting_ReportsDiagnostic() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface I + { + } + + public interface J : I + { + } + + [ComVisible(true)] + public class [|C|] : I + { + } + + """; + + await VerifyAnalyzerAsync(source, enableComHosting: true); + } + + private static Task VerifyAnalyzerAsync(string source, bool enableComHosting) + { + var test = new VerifyCS.Test + { + TestState = + { + Sources = { source }, + AnalyzerConfigFiles = + { + ("/.editorconfig", $""" + is_global = true + build_property.EnableComHosting = {enableComHosting} + """) + } + } + }; + + return test.RunAsync(); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ConvertToGeneratedComInterfaceTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ConvertToGeneratedComInterfaceTests.cs new file mode 100644 index 0000000..a48ca54 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ConvertToGeneratedComInterfaceTests.cs @@ -0,0 +1,329 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.Tasks; +using Xunit; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< + Microsoft.Interop.Analyzers.ConvertComImportToGeneratedComInterfaceAnalyzer, + Microsoft.Interop.Analyzers.ConvertComImportToGeneratedComInterfaceFixer>; + +namespace ComInterfaceGenerator.Unit.Tests +{ + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] + public class ConvertToGeneratedComInterfaceTests + { + [Fact] + public async Task Empty_ReportsDiagnostic() + { + string source = """ + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface [|I|] + { + } + """; + + string fixedSource = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface I + { + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, fixedSource); + } + + [Fact] + public async Task PrimitiveArgument_ReportsDiagnostic() + { + string source = """ + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface [|I|] + { + void Foo(int a); + } + """; + + string fixedSource = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface I + { + void Foo(int a); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, fixedSource); + } + + [Fact] + public async Task Bool_MarshalsAsVariantBool() + { + string source = """ + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface [|I|] + { + bool Foo(bool a); + } + """; + + string fixedSource = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface I + { + [return: MarshalAs(UnmanagedType.VariantBool)] + bool Foo([MarshalAs(UnmanagedType.VariantBool)] bool a); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, fixedSource); + } + + [Fact] + public async Task String_AddsStringMarshallingBStr() + { + string source = """ + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface [|I|] + { + string Foo(string a); + } + """; + + string fixedSource = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface(StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(BStrStringMarshaller))] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface I + { + string Foo(string a); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, fixedSource); + } + + [Fact] + public async Task Array_DoesNotReportDiagnostic() + { + // The default behavior in ComImport for arrays is to marshal as a SAFEARRAY. We don't support SAFEARRAY's, so we don't want to offer a fix here. + string source = """ + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface I + { + void Foo(int[] a); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Fact] + public async Task Delegate_DoesNotReportDiagnostic() + { + // The default behavior in ComImport for delegates is to marshal as a COM object with an undefined interface. We don't support that interface, so we don't offer a fix here. + string source = """ + using System; + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface I + { + void Foo(Action a); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Fact] + public async Task Object_DoesNotReportDiagnostic() + { + // The default behavior in ComImport for Object is to marshal as a VARIANT. We don't support VARIANTs, so we don't offer a fix here. + string source = """ + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface I + { + object Foo(object o); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Fact] + public async Task SystemArray_DoesNotReportDiagnostic() + { + // The default behavior in ComImport for System.Array is to marshal as a COM interface. We don't support that interface, so we don't offer a fix here. + string source = """ + using System; + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface I + { + Array Foo(Array o); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Fact] + public async Task Delegate_WithMarshalAs_ReportsDiagnostic() + { + string source = """ + using System; + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface [|I|] + { + void Foo([MarshalAs(UnmanagedType.FunctionPtr)] Action a); + } + """; + + string fixedSource = """ + using System; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface I + { + void Foo([MarshalAs(UnmanagedType.FunctionPtr)] Action a); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, fixedSource); + } + + [Fact] + public async Task Array_WithMarshalAs_ReportsDiagnostic() + { + string source = """ + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface [|I|] + { + void Foo([MarshalAs(UnmanagedType.LPArray, SizeConst = 10)] int[] a); + } + """; + + string fixedSource = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface I + { + void Foo([MarshalAs(UnmanagedType.LPArray, SizeConst = 10)] int[] a); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, fixedSource); + } + + [Fact] + public async Task InterfaceInheritance_RemovesShadowingMembers() + { + string source = """ + using System.Runtime.InteropServices; + + [ComImport] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface [|I|] + { + void Foo(int a); + } + + [ComImport] + [Guid("F59AB2FE-523D-4B28-911C-21363808C51E")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface [|J|] : I + { + new void Foo(int a); + + void Bar(short a); + } + """; + + string fixedSource = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("5DA39CDF-DCAD-447A-836E-EA80DB34D81B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface I + { + void Foo(int a); + } + + [GeneratedComInterface] + [Guid("F59AB2FE-523D-4B28-911C-21363808C51E")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public partial interface J : I + { + void Bar(short a); + } + """; + + await VerifyCS.VerifyCodeFixAsync(source, fixedSource); + } + } +} 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 index 1258854..32d2801 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs @@ -214,7 +214,7 @@ namespace ComInterfaceGenerator.Unit.Tests _usings + snippet, VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) .WithLocation(0) - .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsIDispatch))); + .WithArguments(TypeNames.ComInterfaceType + "." + nameof(ComInterfaceType.InterfaceIsIDispatch))); } [Fact] @@ -254,7 +254,7 @@ namespace ComInterfaceGenerator.Unit.Tests _usings + snippet, VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) .WithLocation(0) - .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsIInspectable))); + .WithArguments(TypeNames.ComInterfaceType + "." + nameof(ComInterfaceType.InterfaceIsIInspectable))); } [Fact] @@ -294,7 +294,7 @@ namespace ComInterfaceGenerator.Unit.Tests _usings + snippet, VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) .WithLocation(0) - .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsDual))); + .WithArguments(TypeNames.ComInterfaceType + "." + nameof(ComInterfaceType.InterfaceIsDual))); } [Fact] @@ -376,7 +376,7 @@ namespace ComInterfaceGenerator.Unit.Tests _usings + snippet, VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) .WithLocation(0) - .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsIDispatch))); + .WithArguments(TypeNames.ComInterfaceType + "." + nameof(ComInterfaceType.InterfaceIsIDispatch))); } [Fact] @@ -420,7 +420,7 @@ namespace ComInterfaceGenerator.Unit.Tests _usings + snippet, VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) .WithLocation(0) - .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsIInspectable))); + .WithArguments(TypeNames.ComInterfaceType + "." + nameof(ComInterfaceType.InterfaceIsIInspectable))); } [Fact] @@ -464,7 +464,7 @@ namespace ComInterfaceGenerator.Unit.Tests _usings + snippet, VerifyCS.Diagnostic(AnalyzerDiagnostics.InterfaceTypeNotSupported) .WithLocation(0) - .WithArguments(TypeNames.ComInterfaceTypeAttribute + "." + nameof(ComInterfaceType.InterfaceIsDual))); + .WithArguments(TypeNames.ComInterfaceType + "." + nameof(ComInterfaceType.InterfaceIsDual))); } [Fact] diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/RuntimeComApiUsageWithSourceGeneratedComTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/RuntimeComApiUsageWithSourceGeneratedComTests.cs new file mode 100644 index 0000000..19b90f9 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/RuntimeComApiUsageWithSourceGeneratedComTests.cs @@ -0,0 +1,427 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.Tasks; +using Xunit; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpAnalyzerVerifier< + Microsoft.Interop.Analyzers.RuntimeComApiUsageWithSourceGeneratedComAnalyzer>; + +namespace ComInterfaceGenerator.Unit.Tests +{ + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] + public class RuntimeComApiUsageWithSourceGeneratedComTests + { + [Fact] + public async Task SetComObjectData() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComClass] + public class C : I + { + } + + public static class Program + { + public static void Foo(I i) + { + Marshal.SetComObjectData([|i|], new object(), new object()); + } + public static void Foo(C c) + { + Marshal.SetComObjectData([|c|], new object(), new object()); + } + public static void Foo(ComObject c) + { + Marshal.SetComObjectData([|c|], new object(), new object()); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact] + public async Task GetComObjectData() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComClass] + public class C : I + { + } + + public static class Program + { + public static void Foo(I i) + { + _ = Marshal.GetComObjectData([|i|], new object()); + } + public static void Foo(C c) + { + _ = Marshal.GetComObjectData([|c|], new object()); + } + public static void Foo(ComObject c) + { + _ = Marshal.GetComObjectData([|c|], new object()); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact] + public async Task ReleaseComObject() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComClass] + public class C : I + { + } + + public static class Program + { + public static void Foo(I i) + { + _ = Marshal.ReleaseComObject([|i|]); + } + public static void Foo(C c) + { + _ = Marshal.ReleaseComObject([|c|]); + } + public static void Foo(ComObject c) + { + _ = Marshal.ReleaseComObject([|c|]); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact] + public async Task FinalReleaseComObject() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComClass] + public class C : I + { + } + + public static class Program + { + public static void Foo(I i) + { + _ = Marshal.FinalReleaseComObject([|i|]); + } + public static void Foo(C c) + { + _ = Marshal.FinalReleaseComObject([|c|]); + } + public static void Foo(ComObject c) + { + _ = Marshal.FinalReleaseComObject([|c|]); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact] + public async Task CreateAggregatedObject() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComClass] + public class C : I + { + } + + public static class Program + { + public static void Foo(nint outer, I i) + { + _ = Marshal.CreateAggregatedObject(outer, (object)[|i|]); + _ = Marshal.CreateAggregatedObject(outer, [|i|]); + _ = Marshal.CreateAggregatedObject<[|I|]>(outer, [|i|]); + } + public static void Foo(nint outer, C c) + { + _ = Marshal.CreateAggregatedObject(outer, (object)[|c|]); + _ = Marshal.CreateAggregatedObject(outer, [|c|]); + _ = Marshal.CreateAggregatedObject<[|C|]>(outer, [|c|]); + } + public static void Foo(nint outer, ComObject c) + { + _ = Marshal.CreateAggregatedObject(outer, (object)[|c|]); + _ = Marshal.CreateAggregatedObject(outer, [|c|]); + _ = Marshal.CreateAggregatedObject<[|ComObject|]>(outer, [|c|]); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact] + public async Task CreateWrapperOfType() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface J + { + } + + [GeneratedComClass] + public class CI : I + { + } + + [GeneratedComClass] + public class CJ : J + { + } + + public static class Program + { + public static void Foo(I i) + { + _ = Marshal.CreateWrapperOfType([|i|], typeof([|J|])); + _ = Marshal.CreateWrapperOfType<[|I|], [|J|]>([|i|]); + _ = Marshal.CreateWrapperOfType([|i|], typeof([|CI|])); + _ = Marshal.CreateWrapperOfType<[|I|], [|CI|]>([|i|]); + _ = Marshal.CreateWrapperOfType<[|I|], [|ComObject|]>([|i|]); + } + + public static void Foo(CI i) + { + _ = Marshal.CreateWrapperOfType([|i|], typeof([|J|])); + _ = Marshal.CreateWrapperOfType<[|CI|], [|J|]>([|i|]); + _ = Marshal.CreateWrapperOfType([|i|], typeof([|CJ|])); + _ = Marshal.CreateWrapperOfType<[|CI|], [|CJ|]>([|i|]); + _ = Marshal.CreateWrapperOfType<[|CI|], [|ComObject|]>([|i|]); + } + + public static void Foo(ComObject i) + { + _ = Marshal.CreateWrapperOfType([|i|], typeof([|J|])); + _ = Marshal.CreateWrapperOfType<[|ComObject|], [|J|]>([|i|]); + _ = Marshal.CreateWrapperOfType([|i|], typeof([|CJ|])); + _ = Marshal.CreateWrapperOfType<[|ComObject|], [|CJ|]>([|i|]); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact] + public async Task GetTypedObjectForIUnknown() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComClass] + public class C : I + { + } + + public static class Program + { + public static void Foo(nint unknown) + { + _ = Marshal.GetTypedObjectForIUnknown(unknown, typeof([|I|])); + _ = Marshal.GetTypedObjectForIUnknown(unknown, typeof([|C|])); + _ = Marshal.GetTypedObjectForIUnknown(unknown, typeof([|ComObject|])); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact] + public async Task GetIUnknownForObject() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComClass] + public class C : I + { + } + + public static class Program + { + public static void Foo(I i) + { + _ = Marshal.GetIUnknownForObject([|i|]); + } + public static void Foo(C c) + { + _ = Marshal.GetIUnknownForObject([|c|]); + } + public static void Foo(ComObject c) + { + _ = Marshal.GetIUnknownForObject([|c|]); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact] + public async Task GetIDispatchForObject() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComClass] + public class C : I + { + } + + public static class Program + { + public static void Foo(I i) + { + _ = Marshal.GetIDispatchForObject([|i|]); + } + public static void Foo(C c) + { + _ = Marshal.GetIDispatchForObject([|c|]); + } + public static void Foo(ComObject c) + { + _ = Marshal.GetIDispatchForObject([|c|]); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact] + public async Task GetComInterfaceForObject() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")] + public interface I + { + } + + [GeneratedComClass] + public class C : I + { + } + + public static class Program + { + public static void Foo(I i) + { + _ = Marshal.GetComInterfaceForObject([|i|], typeof([|I|])); + _ = Marshal.GetComInterfaceForObject([|i|], typeof([|I|]), CustomQueryInterfaceMode.Allow); + _ = Marshal.GetComInterfaceForObject<[|I|], [|I|]>([|i|]); + } + + public static void Foo(C c) + { + _ = Marshal.GetComInterfaceForObject([|c|], typeof([|C|])); + _ = Marshal.GetComInterfaceForObject([|c|], typeof([|C|]), CustomQueryInterfaceMode.Allow); + _ = Marshal.GetComInterfaceForObject<[|C|], [|C|]>([|c|]); + + } + + public static void Foo(ComObject c) + { + _ = Marshal.GetComInterfaceForObject([|c|], typeof([|ComObject|])); + _ = Marshal.GetComInterfaceForObject([|c|], typeof([|ComObject|]), CustomQueryInterfaceMode.Allow); + _ = Marshal.GetComInterfaceForObject<[|ComObject|], [|ComObject|]>([|c|]); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(source); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs index 14bb0e4..4bc8194 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; +using System.Collections.Immutable; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks; @@ -9,6 +11,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.Interop.Analyzers; using Xunit; +using static Microsoft.Interop.Analyzers.ConvertToSourceGeneratedInteropFixer; using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< Microsoft.Interop.Analyzers.ConvertToLibraryImportAnalyzer, @@ -19,7 +22,7 @@ namespace LibraryImportGenerator.UnitTests [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] public class ConvertToLibraryImportFixerTests { - private const string ConvertToLibraryImportKey = "ConvertToLibraryImport,"; + private const string ConvertToLibraryImportKey = "ConvertToLibraryImport"; [Fact] public async Task Basic() @@ -299,7 +302,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ImmutableDictionary.Empty); string fixedSourceWithSuffix = $$""" using System.Runtime.InteropServices; partial class Test @@ -308,7 +311,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithSuffix, $"{ConvertToLibraryImportKey}{suffix},"); + await VerifyCodeFixAsync(source, fixedSourceWithSuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String(suffix.ToString()) } }); } [Fact] @@ -332,7 +335,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ImmutableDictionary.Empty); string fixedSourceWithASuffix = """ using System.Runtime.InteropServices; @@ -342,7 +345,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}A,"); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("A") } }); string fixedSourceWithWSuffix = """ using System.Runtime.InteropServices; @@ -352,7 +355,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithWSuffix, $"{ConvertToLibraryImportKey}W,"); + await VerifyCodeFixAsync(source, fixedSourceWithWSuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("W") } }); } [Fact] @@ -376,7 +379,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ImmutableDictionary.Empty); string fixedSourceWithASuffix = """ using System.Runtime.InteropServices; @@ -386,7 +389,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}A,"); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("A") } }); } [Fact] @@ -412,7 +415,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}A,"); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("A") } }); } [Fact] @@ -436,7 +439,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}A,"); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("A") } }); } [Fact] @@ -462,7 +465,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}A,"); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("A") } }); } [Fact] @@ -486,7 +489,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}A,"); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("A") } }); } [InlineData(CharSet.Ansi, 'A')] @@ -510,7 +513,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ImmutableDictionary.Empty); } [Fact] @@ -534,7 +537,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ImmutableDictionary.Empty); string fixedSourceWithASuffix = """ using System.Runtime.InteropServices; @@ -544,7 +547,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}A,"); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("A") } }); } [Fact] @@ -568,7 +571,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceNoSuffix, ImmutableDictionary.Empty); string fixedSourceWithASuffix = """ using System.Runtime.InteropServices; @@ -578,7 +581,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, $"{ConvertToLibraryImportKey}W,"); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("W") } }); } [Fact] @@ -602,7 +605,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithNoAdditionalSuffix, $"{ConvertToLibraryImportKey}A,"); + await VerifyCodeFixAsync(source, fixedSourceWithNoAdditionalSuffix, new Dictionary { { ConvertToLibraryImportFixer.SelectedSuffixOption, new Option.String("A") } }); } [Fact] @@ -628,7 +631,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ImmutableDictionary.Empty); } [Fact] @@ -652,7 +655,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:MethodA|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ImmutableDictionary.Empty); } [Fact] @@ -678,7 +681,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:Method|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ImmutableDictionary.Empty); } [Fact] @@ -702,7 +705,7 @@ namespace LibraryImportGenerator.UnitTests public static partial void {|CS8795:MethodA|}(); } """; - await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ConvertToLibraryImportKey); + await VerifyCodeFixAsync(source, fixedSourceWithASuffix, ImmutableDictionary.Empty); } [Fact] @@ -866,7 +869,7 @@ namespace LibraryImportGenerator.UnitTests await VerifyCodeFixNoUnsafeAsync( source, fixedSource, - $"{ConvertToLibraryImportKey}AddUnsafe,"); + new Dictionary { { Option.AllowUnsafe, new Option.Bool(true) } }); } [Fact] @@ -906,7 +909,7 @@ namespace LibraryImportGenerator.UnitTests await VerifyCodeFixAsync( source, fixedSource, - ConvertToLibraryImportKey); + ImmutableDictionary.Empty); } [Fact] @@ -947,12 +950,12 @@ namespace LibraryImportGenerator.UnitTests await VerifyCodeFixAsync( source, source, - ConvertToLibraryImportKey); + ImmutableDictionary.Empty); await VerifyCodeFixAsync( source, fixedSource, - $"{ConvertToLibraryImportKey}{ConvertToLibraryImportAnalyzer.MayRequireAdditionalWork},"); + new Dictionary { { Option.MayRequireAdditionalWork, new Option.Bool(true) } }); } [Fact] @@ -1013,7 +1016,7 @@ namespace LibraryImportGenerator.UnitTests await VerifyCodeFixAsync( source, blittableOnlyFixedSource, - ConvertToLibraryImportKey); + ImmutableDictionary.Empty); } [Fact] @@ -1103,7 +1106,7 @@ namespace LibraryImportGenerator.UnitTests source, nonBlittableOnlyFixedSource, allFixedSource, - $"{ConvertToLibraryImportKey}{ConvertToLibraryImportAnalyzer.MayRequireAdditionalWork},"); + new Dictionary { { Option.MayRequireAdditionalWork, new Option.Bool(true) } }); } private static async Task VerifyCodeFixAsync(string source, string fixedSource) @@ -1117,13 +1120,13 @@ namespace LibraryImportGenerator.UnitTests await test.RunAsync(); } - private static async Task VerifyCodeFixAsync(string source, string fixedSource, string equivalenceKey) + private static async Task VerifyCodeFixAsync(string source, string fixedSource, IDictionary options) { var test = new VerifyCS.Test { TestCode = source, FixedCode = fixedSource, - CodeActionEquivalenceKey = equivalenceKey, + CodeActionEquivalenceKey = Option.CreateEquivalenceKeyFromOptions(ConvertToLibraryImportKey, options.ToImmutableDictionary()), }; test.FixedState.MarkupHandling = Microsoft.CodeAnalysis.Testing.MarkupMode.Allow; @@ -1131,14 +1134,14 @@ namespace LibraryImportGenerator.UnitTests await test.RunAsync(); } - private static async Task VerifyCodeFixAsync(string source, string fixedSource, string batchFixedSource, string equivalenceKey) + private static async Task VerifyCodeFixAsync(string source, string fixedSource, string batchFixedSource, IDictionary options) { var test = new VerifyCS.Test { TestCode = source, FixedCode = fixedSource, BatchFixedCode = batchFixedSource, - CodeActionEquivalenceKey = equivalenceKey, + CodeActionEquivalenceKey = Option.CreateEquivalenceKeyFromOptions(ConvertToLibraryImportKey, options.ToImmutableDictionary()), }; test.FixedState.MarkupHandling = Microsoft.CodeAnalysis.Testing.MarkupMode.Allow; @@ -1146,13 +1149,13 @@ namespace LibraryImportGenerator.UnitTests await test.RunAsync(); } - private static async Task VerifyCodeFixNoUnsafeAsync(string source, string fixedSource, string equivalenceKey) + private static async Task VerifyCodeFixNoUnsafeAsync(string source, string fixedSource, IDictionary options) { var test = new TestNoUnsafe { TestCode = source, FixedCode = fixedSource, - CodeActionEquivalenceKey = equivalenceKey, + CodeActionEquivalenceKey = Option.CreateEquivalenceKeyFromOptions(ConvertToLibraryImportKey, options.ToImmutableDictionary()), }; await test.RunAsync();