diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs index 215b6a7cc..d70160642 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs @@ -486,6 +486,9 @@ public static void ImplType( implType.Methods.Add(makeVectorChangedMethod); implType.Methods.Add(get_VectorChangedTableMethod); implType.Properties.Add(vectorChangedTableProperty); + + // Track the type (it may be needed by COM interface entries for user-defined types) + emitState.TrackTypeDefinition(implType, vectorType, "Impl"); } /// diff --git a/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.Generics.cs b/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.Generics.cs new file mode 100644 index 000000000..593d5640a --- /dev/null +++ b/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.Generics.cs @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using AsmResolver.DotNet; +using AsmResolver.DotNet.Signatures; +using WindowsRuntime.InteropGenerator.Errors; +using WindowsRuntime.InteropGenerator.Generation; +using WindowsRuntime.InteropGenerator.Helpers; +using WindowsRuntime.InteropGenerator.References; +using WindowsRuntime.InteropGenerator.Visitors; + +namespace WindowsRuntime.InteropGenerator.Discovery; + +/// +internal partial class InteropTypeDiscovery +{ + /// + /// Tries to track a constructed generic type. + /// + /// The for the constructed type to analyze. + /// The arguments for this invocation. + /// The discovery state for this invocation. + /// The instance to use. + /// The module currently being analyzed. + public static void TryTrackGenericTypeInstance( + GenericInstanceTypeSignature typeSignature, + InteropGeneratorArgs args, + InteropGeneratorDiscoveryState discoveryState, + InteropReferences interopReferences, + ModuleDefinition module) + { + // Ignore types that should explicitly be excluded + if (TypeExclusions.IsExcluded(typeSignature, interopReferences)) + { + return; + } + + // Filter all constructed generic type signatures we have. We don't care about generic type + // definitions (eg. 'TypedEventHandler`1') for the purposes of marshalling code. + if (!typeSignature.AcceptVisitor(IsConstructedGenericTypeVisitor.Instance)) + { + return; + } + + // Ignore types that are not fully resolvable (this likely means a .dll is missing) + if (!typeSignature.IsFullyResolvable(out TypeDefinition? typeDefinition)) + { + // Log a warning the first time we fail to resolve this generic instantiation in this module + if (discoveryState.TrackFailedResolutionType(typeSignature, module)) + { + WellKnownInteropExceptions.GenericTypeSignatureNotResolvedError(typeSignature, module).LogOrThrow(args.TreatWarningsAsErrors); + } + + return; + } + + // If the current type signature represents a Windows Runtime type, track it + if (typeSignature.IsWindowsRuntimeType(interopReferences)) + { + TryTrackWindowsRuntimeGenericTypeInstance( + typeDefinition, + typeSignature, + args, + discoveryState, + interopReferences, + module); + } + else + { + // Otherwise, try to track information for some constructed managed type + TryTrackManagedGenericTypeInstance( + typeDefinition, + typeSignature, + args, + discoveryState, + interopReferences); + } + } + + /// + /// Tries to track an SZ array type. + /// + /// The for the SZ array type to analyze. + /// The arguments for this invocation. + /// The discovery state for this invocation. + /// The instance to use. + /// The module currently being analyzed. + public static void TryTrackSzArrayType( + SzArrayTypeSignature typeSignature, + InteropGeneratorArgs args, + InteropGeneratorDiscoveryState discoveryState, + InteropReferences interopReferences, + ModuleDefinition module) + { + // Ignore types that should explicitly be excluded + if (TypeExclusions.IsExcluded(typeSignature, interopReferences)) + { + return; + } + + // Filter all constructed generic type signatures we have. We don't care about + // generic type definitions (eg. '!0[]') for the purposes of marshalling code. + if (!typeSignature.AcceptVisitor(IsConstructedGenericTypeVisitor.Instance)) + { + return; + } + + // Ignore types that are not fully resolvable (this likely means a .dll is missing) + if (!typeSignature.IsFullyResolvable(out _)) + { + // Log a warning the first time we fail to resolve this SZ array in this module + if (discoveryState.TrackFailedResolutionType(typeSignature, module)) + { + WellKnownInteropExceptions.SzArrayTypeSignatureNotResolvedError(typeSignature, module).LogOrThrow(args.TreatWarningsAsErrors); + } + + return; + } + + // Ignore array types that are not Windows Runtime types + if (!typeSignature.IsWindowsRuntimeType(interopReferences)) + { + return; + } + + // Track all SZ array types, as we'll need to emit marshalling code for them + discoveryState.TrackSzArrayType(typeSignature); + } + + /// + /// Tries to track a constructed generic Windows Runtime type. + /// + /// The for the type to analyze. + /// The for the constructed type to analyze. + /// The arguments for this invocation. + /// The discovery state for this invocation. + /// The instance to use. + /// The module currently being analyzed. + private static void TryTrackWindowsRuntimeGenericTypeInstance( + TypeDefinition typeDefinition, + GenericInstanceTypeSignature typeSignature, + InteropGeneratorArgs args, + InteropGeneratorDiscoveryState discoveryState, + InteropReferences interopReferences, + ModuleDefinition module) + { + // Gather all 'KeyValuePair<,>' instances + if (typeSignature.IsValueType && typeSignature.IsConstructedKeyValuePairType(interopReferences)) + { + discoveryState.TrackKeyValuePairType(typeSignature); + + return; + } + + // Gather all Windows Runtime delegate types. We want to gather all projected delegate types, plus + // any custom-mapped ones (e.g. 'EventHandler' and 'EventHandler'). + // The filtering is already done above, so here we can rely the type will be of one of those kinds. + if (typeDefinition.IsDelegate) + { + discoveryState.TrackGenericDelegateType(typeSignature); + + return; + } + + // Track all projected Windows Runtime generic interfaces + if (typeDefinition.IsInterface) + { + discoveryState.TrackGenericInterfaceType(typeSignature, interopReferences); + + // We also want to crawl base interfaces + foreach (TypeSignature interfaceSignature in typeSignature.EnumerateAllInterfaces()) + { + // Filter out just constructed generic interfaces, since we only care about those here. + // The non-generic ones are only useful when gathering interfaces for user-defined types. + if (interfaceSignature is not GenericInstanceTypeSignature constructedSignature) + { + continue; + } + + if (!interfaceSignature.IsFullyResolvable(out _)) + { + // Also log a warning the first time we fail to resolve one of the recursively discovered generic + // instantiations from this module. The enumeration also yields back interfaces that couldn't be + // resolved, as that step is performed after yielding. This is done so we can have our own logic + // to log warnings or throw errors from here while we're processing interfaces in this module. + if (discoveryState.TrackFailedResolutionType(interfaceSignature, module)) + { + WellKnownInteropExceptions.GenericTypeSignatureNotResolvedError(interfaceSignature, module).LogOrThrow(args.TreatWarningsAsErrors); + } + + continue; + } + + discoveryState.TrackGenericInterfaceType(constructedSignature, interopReferences); + } + } + } + + /// + /// Tries to track a constructed generic user-defined type. + /// + /// The for the type to analyze. + /// The for the constructed type to analyze. + /// The arguments for this invocation. + /// The discovery state for this invocation. + /// The instance to use. + private static void TryTrackManagedGenericTypeInstance( + TypeDefinition typeDefinition, + GenericInstanceTypeSignature typeSignature, + InteropGeneratorArgs args, + InteropGeneratorDiscoveryState discoveryState, + InteropReferences interopReferences) + { + // Check for all '[ReadOnly]Span' types in particular, and track them as SZ array types. + // This is because "pass-array" and "fill-array" parameters are projected using spans, but + // those projections require the marshalling code produced when discovering SZ array types. + // So if we see any of these spans where the element type is a Windows Runtime type, we + // manually construct an SZ array type for it and add it to the set of tracked array types. + if (typeSignature.IsValueType && + typeSignature.IsConstructedSpanOrReadOnlySpanType(interopReferences) && + typeSignature.TypeArguments[0].IsWindowsRuntimeType(interopReferences)) + { + discoveryState.TrackSzArrayType(typeSignature.TypeArguments[0].MakeSzArrayType()); + + return; + } + + // Otherwise, try to track a constructed user-defined type + TryTrackExposedUserDefinedType( + typeDefinition, + typeSignature, + args, + discoveryState, + interopReferences); + } +} \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.cs b/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.cs new file mode 100644 index 000000000..3a6f8b9a9 --- /dev/null +++ b/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.cs @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using AsmResolver.DotNet; +using AsmResolver.DotNet.Signatures; +using WindowsRuntime.InteropGenerator.Errors; +using WindowsRuntime.InteropGenerator.Generation; +using WindowsRuntime.InteropGenerator.Helpers; +using WindowsRuntime.InteropGenerator.Models; +using WindowsRuntime.InteropGenerator.References; + +namespace WindowsRuntime.InteropGenerator.Discovery; + +/// +/// A discovery helper type for interop types. +/// +internal static partial class InteropTypeDiscovery +{ + /// + /// A thread-local instance that can be reused by discovery logic. + /// + [ThreadStatic] + private static TypeSignatureEquatableSet.Builder? TypeSignatures; + + /// + /// Tries to track a given composable Windows Runtime type. + /// + /// The for the type to analyze. + /// The arguments for this invocation. + /// The discovery state for this invocation. + public static void TryTrackTypeHierarchyType( + TypeDefinition typeDefinition, + InteropGeneratorArgs args, + InteropGeneratorDiscoveryState discoveryState) + { + // We only care about projected Windows Runtime classes + if (!typeDefinition.IsProjectedWindowsRuntimeClassType) + { + return; + } + + // Ignore types that don't have another base class + if (!typeDefinition.HasBaseType(out ITypeDefOrRef? baseType)) + { + return; + } + + // We need to resolve the base type to be able to look up attributes on it + if (!baseType.IsFullyResolvable(out _)) + { + WellKnownInteropExceptions.WindowsRuntimeClassTypeNotResolvedWarning(baseType, typeDefinition).LogOrThrow(args.TreatWarningsAsErrors); + + return; + } + + // If the base type is also a projected Windows Runtime type, track it + if (baseType.IsProjectedWindowsRuntimeType) + { + discoveryState.TrackTypeHierarchyEntry(typeDefinition.FullName, baseType.FullName); + } + } + + /// + /// Tries to track an exposed user-defined type. + /// + /// The for the type to analyze. + /// The for the type to analyze. + /// The arguments for this invocation. + /// The discovery state for this invocation. + /// The instance to use. + /// + /// This method expects to either be non-generic, or + /// to have be a fully constructed signature for it. + /// + public static void TryTrackExposedUserDefinedType( + TypeDefinition typeDefinition, + TypeSignature typeSignature, + InteropGeneratorArgs args, + InteropGeneratorDiscoveryState discoveryState, + InteropReferences interopReferences) + { + // Ignore types that should explicitly be excluded + if (TypeExclusions.IsExcluded(typeDefinition, interopReferences)) + { + return; + } + + // Ignore all type definitions with generic parameters where we don't have constructed + // generic type signature. We can track these separately when we see them as instantiated. + if (typeDefinition.HasGenericParameters && typeSignature is not GenericInstanceTypeSignature) + { + return; + } + + // We can skip all projected Windows Runtime types early, as they don't need CCW support + if (typeDefinition.IsProjectedWindowsRuntimeType) + { + return; + } + + // We'll need to look up attributes and enumerate interfaces across the entire type + // hierarchy for this type, so make sure that we can resolve all types from it first. + if (!typeDefinition.IsTypeHierarchyFullyResolvable(out ITypeDefOrRef? failedResolutionBaseType)) + { + WellKnownInteropExceptions.UserDefinedTypeNotFullyResolvedWarning(failedResolutionBaseType, typeDefinition).LogOrThrow(args.TreatWarningsAsErrors); + + return; + } + + // We only want to process non-generic user-defined types that are potentially exposed to Windows Runtime + if (!typeDefinition.IsPossiblyWindowsRuntimeExposedType || typeDefinition.IsWindowsRuntimeManagedOnlyType(interopReferences)) + { + return; + } + + // Reuse the thread-local builder to track all implemented interfaces for the current type + TypeSignatureEquatableSet.Builder interfaces = TypeSignatures ??= new TypeSignatureEquatableSet.Builder(); + + // Since we're reusing the builder for all types, make sure to clear it first + interfaces.Clear(); + + // We want to explicitly track whether the type implements any projected Windows Runtime + // interfaces, as we are only interested in such types. We want to also gather all + // implemented '[GeneratedComInterface]' interfaces, but if a type only implements + // those, we will ignore it. Such types should be marshalled via 'ComWrappers' directly. + bool hasAnyProjectedWindowsRuntimeInterfaces = false; + + // Gather all implemented Windows Runtime interfaces for the current type + foreach (TypeSignature interfaceSignature in typeSignature.EnumerateAllInterfaces()) + { + // Make sure we can resolve the interface type fully, which we should always be able to do. + // This can really only fail for some constructed generics, for invalid type arguments. + if (!interfaceSignature.IsFullyResolvable(out TypeDefinition? interfaceDefinition)) + { + WellKnownInteropExceptions.InterfaceImplementationTypeNotResolvedWarning(interfaceSignature, typeDefinition).LogOrThrow(args.TreatWarningsAsErrors); + + continue; + } + + // Check for projected Windows Runtime interfaces first + if (interfaceSignature.IsWindowsRuntimeType(interopReferences)) + { + hasAnyProjectedWindowsRuntimeInterfaces = true; + + interfaces.Add(interfaceSignature); + + // If the current interface is generic, also make sure that it's tracked. This is needed + // to fully cover all possible constructed generic interface types that might be needed. + // For instance, consider this case: + // + // class A : IEnumerable; + // class B : A; + // + // While processing 'B', we'll discover the constructed 'IEnumerable' interface. + // This interface would not have been discovered when processing 'A', as it's not + // in the 'TypeSpec' metadata table, and only appears as unconstructed on 'A'. + // So the discovery logic for generic instantiations below would otherwise miss it. + if (interfaceSignature is GenericInstanceTypeSignature constructedSignature) + { + discoveryState.TrackGenericInterfaceType(constructedSignature, interopReferences); + } + } + else if (interfaceDefinition.IsGeneratedComInterfaceType) + { + // We can only gather this type if we can find the generated 'InterfaceInformation' type. + // If we can't find it, we can't add the interface to the list of interface entries. We + // should warn if that's the (unlikely) case, so users can at least know that something + // is wrong. Otherwise we'd just silently ignore these types, resulting in runtime failures. + if (!interfaceDefinition.TryGetInterfaceInformationType(interopReferences, out _)) + { + WellKnownInteropExceptions.GeneratedComInterfaceImplementationTypeNotFoundWarning(interfaceDefinition, typeDefinition).LogOrThrow(args.TreatWarningsAsErrors); + + continue; + } + + // Ensure we can get the '[GuidAttribute]' from the interface. We need this at compile time + // so we can check against some specific IID which might affect how we construct the COM + // interface entries. For instance, we need to check whether 'IMarshal' is implemented. + if (!interfaceDefinition.TryGetGuidAttribute(interopReferences, out Guid iid)) + { + WellKnownInteropExceptions.GeneratedComInterfaceGuidAttributeNotFoundWarning(interfaceDefinition, typeDefinition).LogOrThrow(args.TreatWarningsAsErrors); + + continue; + } + + // Validate that the current interface isn't trying to implement a reserved interface. + // For instance, it's not allowed to try to explicitly implement 'IUnknown' or 'IInspectable'. + if (WellKnownInterfaceIIDs.ReservedIIDsMap.TryGetValue(iid, out string? interfaceName)) + { + throw WellKnownInteropExceptions.GeneratedComInterfaceReservedGuidError(interfaceDefinition, typeDefinition, iid, interfaceName); + } + + // Also track all '[GeneratedComInterface]' interfaces too, and filter them later (below) + interfaces.Add(interfaceSignature); + } + } + + // If the user-defined type implements at least a Windows Runtime interface, then it's considered exposed. + // We don't want to handle marshalling code for types with only '[GeneratedComInterface]' interfaces. + if (hasAnyProjectedWindowsRuntimeInterfaces) + { + discoveryState.TrackUserDefinedType(typeSignature, interfaces.ToEquatableSet()); + } + } +} \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs index 42357863e..50d273efe 100644 --- a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs +++ b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs @@ -430,11 +430,11 @@ public static WellKnownInteropException CustomMappedTypeComWrappersMarshallerAtt } /// - /// Failed to resolve a '[GeneratedComInterface]' type. + /// Failed to resolve the type of an implemented interface. /// - public static WellKnownInteropWarning GeneratedComInterfaceTypeNotResolvedWarning(TypeSignature interfaceType, TypeDefinition type) + public static WellKnownInteropWarning InterfaceImplementationTypeNotResolvedWarning(TypeSignature interfaceType, TypeDefinition type) { - return Warning(49, $"Failed to resolve the '[GeneratedComInterface]' type '{interfaceType}' while processing type '{type}': the interface will not be included in the set of available COM interface entries."); + return Warning(49, $"Failed to resolve interface type '{interfaceType}' while processing type '{type}': the interface will not be included in the set of available COM interface entries."); } /// @@ -534,11 +534,11 @@ public static WellKnownInteropWarning GeneratedComInterfaceGuidAttributeNotFound } /// - /// Failed to resolve a Windows Runtime interface type. + /// Failed to resolve a base type for a user-defined type. /// - public static WellKnownInteropWarning WindowsRuntimeInterfaceTypeNotResolvedWarning(TypeSignature interfaceType, TypeDefinition type) + public static WellKnownInteropWarning UserDefinedTypeNotFullyResolvedWarning(ITypeDefOrRef baseType, TypeDefinition type) { - return Warning(62, $"Failed to resolve the Windows Runtime interface type '{interfaceType}' while processing type '{type}': the interface will not be included in the set of available COM interface entries."); + return Warning(62, $"Failed to resolve the base type '{baseType}' in the type hierarchy for user-defined type '{type}': marshalling code for it will not be generated."); } /// @@ -573,14 +573,6 @@ public static WellKnownInteropWarning WindowsRuntimeClassTypeNotResolvedWarning( return Warning(66, $"Failed to resolve the base type '{baseType}' for Windows Runtime class type '{classType}': runtime casts to the base type will not work if the type is trimmed."); } - /// - /// Failed to resolve a base type for a user-defined type. - /// - public static WellKnownInteropWarning UserDefinedTypeNotFullyResolvedWarning(ITypeDefOrRef baseType, TypeDefinition type) - { - return Warning(67, $"Failed to resolve the base type '{baseType}' in the type hierarchy for user-defined type '{type}': marshalling code for it will not be generated."); - } - /// /// Creates a new exception with the specified id and message. /// diff --git a/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.cs b/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.cs index ac8ffeaac..aeee73acb 100644 --- a/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.cs @@ -8,6 +8,7 @@ using AsmResolver.DotNet; using AsmResolver.DotNet.Code.Cil; using AsmResolver.DotNet.Signatures; +using AsmResolver.PE.DotNet.Cil; using AsmResolver.PE.DotNet.Metadata.Tables; using WindowsRuntime.InteropGenerator.Helpers; using WindowsRuntime.InteropGenerator.Visitors; @@ -230,6 +231,58 @@ static IEnumerable EnumerateTypeSignatures( yield return result; } } + + IReadOnlyList instructions = specification.Method!.Resolve()?.CilMethodBody?.Instructions ?? (IReadOnlyList)[]; + + // Go through instruction to look for new objects + foreach (CilInstruction instruction in instructions) + { + // We only care for 'newobj' instructions + if (instruction.OpCode != CilOpCodes.Newobj) + { + continue; + } + + // Check that we can retrieve the target object type + if (instruction.Operand is not IMethodDefOrRef { DeclaringType: ITypeDefOrRef objectType }) + { + continue; + } + + // Instantiate the object type and enumerate all signatures + foreach (TResult result in EnumerateTypeSignatures( + objectType.ToTypeSignature().InstantiateGenericTypes(genericContext), + results, + visitor)) + { + yield return result; + } + } + + // Go through instruction to look for new arrays + foreach (CilInstruction instruction in instructions) + { + // We only care for 'newarr' instructions + if (instruction.OpCode != CilOpCodes.Newarr) + { + continue; + } + + // Check that we can retrieve the target object type + if (instruction.Operand is not ITypeDefOrRef arrayType) + { + continue; + } + + // Instantiate the object type and enumerate all signatures + foreach (TResult result in EnumerateTypeSignatures( + arrayType.ToTypeSignature().InstantiateGenericTypes(genericContext), + results, + visitor)) + { + yield return result; + } + } } } diff --git a/src/WinRT.Interop.Generator/Extensions/TypeDefinitionExtensions.cs b/src/WinRT.Interop.Generator/Extensions/TypeDefinitionExtensions.cs index 515518250..e831a8e68 100644 --- a/src/WinRT.Interop.Generator/Extensions/TypeDefinitionExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/TypeDefinitionExtensions.cs @@ -25,6 +25,17 @@ internal static class TypeDefinitionExtensions /// public bool IsStatic => type.IsAbstract && type.IsSealed; + /// + /// Gets whether a given type has a base type other than . + /// + /// The resulting base type, if available. + public bool HasBaseType([NotNullWhen(true)] out ITypeDefOrRef? baseType) + { + baseType = type.BaseType; + + return baseType is not (null or CorLibTypeSignature { ElementType: ElementType.Object }); + } + /// /// Gets a value indicating whether a given 's type hierarchy can be fully resolved to type definitions. /// @@ -32,18 +43,16 @@ internal static class TypeDefinitionExtensions /// Whether the input 's type hierarchy can be fully resolved to type definitions. public bool IsTypeHierarchyFullyResolvable([NotNullWhen(false)] out ITypeDefOrRef? failedResolutionBaseType) { - ITypeDefOrRef? baseType = type.BaseType; + TypeDefinition currentDefinition = type; - while (baseType is not (null or CorLibTypeSignature { ElementType: ElementType.Object })) + while (currentDefinition.HasBaseType(out ITypeDefOrRef? baseType)) { - if (!baseType.IsFullyResolvable(out TypeDefinition? baseDefinition)) + if (!baseType.IsFullyResolvable(out currentDefinition!)) { failedResolutionBaseType = baseType; return false; } - - baseType = baseDefinition.BaseType; } failedResolutionBaseType = null; @@ -224,38 +233,18 @@ public IEnumerable EnumerateBaseTypesAndSelf() { yield return type; - ITypeDefOrRef? baseType = type.BaseType; + TypeDefinition currentDefinition = type; - while (baseType is not (null or CorLibTypeSignature { ElementType: ElementType.Object })) + while (currentDefinition.HasBaseType(out ITypeDefOrRef? baseType)) { // If we can't resolve the current base type, we have to stop. // Callers should validate the type hierarchy before calling this. - if (!baseType.IsFullyResolvable(out TypeDefinition? baseDefinition)) + if (!baseType.IsFullyResolvable(out currentDefinition!)) { yield break; } - yield return baseDefinition; - - baseType = baseDefinition.BaseType; - } - } - - /// - /// Enumerates all interface types implementation by the specified type, including those implemented by base types. - /// - /// The sequence of interface types implemented by the input type. - /// - /// This method might return the same interface types multiple times, if implemented by multiple types in the hierarchy. - /// - public IEnumerable EnumerateAllInterfaces() - { - foreach (TypeDefinition currentType in type.EnumerateBaseTypesAndSelf()) - { - foreach (InterfaceImplementation implementation in currentType.Interfaces) - { - yield return implementation; - } + yield return currentDefinition; } } diff --git a/src/WinRT.Interop.Generator/Extensions/TypeSignatureExtensions.cs b/src/WinRT.Interop.Generator/Extensions/TypeSignatureExtensions.cs index be76c72f1..cc0a7fbcc 100644 --- a/src/WinRT.Interop.Generator/Extensions/TypeSignatureExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/TypeSignatureExtensions.cs @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using AsmResolver.DotNet; using AsmResolver.DotNet.Signatures; +using AsmResolver.PE.DotNet.Metadata.Tables; namespace WindowsRuntime.InteropGenerator; @@ -43,5 +45,65 @@ public bool IsFullyResolvable([NotNullWhen(true)] out TypeDefinition? definition return true; } + + /// + /// Enumerates all interface types implementation by the specified type, including those implemented by base types. + /// + /// The sequence of interface types implemented by the input type. + /// + /// This method might return the same interface types multiple times, if implemented by multiple types in the hierarchy. + /// + public IEnumerable EnumerateAllInterfaces() + { + TypeSignature currentSignature = signature; + + while (currentSignature is not null) + { + // If we can't resolve the current type signature, we have to stop. + // Callers should validate the type hierarchy before calling this. + if (!currentSignature.IsFullyResolvable(out TypeDefinition? currentDefinition)) + { + yield break; + } + + GenericContext context = new(currentSignature as GenericInstanceTypeSignature, null); + + // Go over all interfaces implemented on the current type. We don't need + // to recurse on them, as classes always declare the full transitive set. + foreach (InterfaceImplementation interfaceImplementation in currentDefinition.Interfaces) + { + // Ignore this interface if we can't actually retrieve the interface type. + // This should never happen for valid .NET assemblies, but just in case. + if (interfaceImplementation.Interface?.ToReferenceTypeSignature() is not TypeSignature interfaceSignature) + { + continue; + } + + // Return either the current non-generic interface, or the constructed generic one. + // We don't have to check: if the interface is not generic, this will be a no-op. + yield return interfaceSignature.InstantiateGenericTypes(context); + + // Also recurse on the base interfaces (no need to instantiate the returned interface type + // signatures for base interfaces here: they will be already instantiate when returned). + foreach (TypeSignature baseInterface in interfaceSignature.EnumerateAllInterfaces()) + { + yield return baseInterface; + } + } + + ITypeDefOrRef? baseType = currentDefinition.BaseType; + + // Stop if we have no available base type or if we reached 'object' + if (baseType is null or CorLibTypeSignature { ElementType: ElementType.Object }) + { + yield break; + } + + // Get the signature for the base type, adding back any generic context. + // Note that the base type will always be a reference type, even for + // struct types (in that case, the base type will be 'System.ValueType'). + currentSignature = baseType.ToReferenceTypeSignature().InstantiateGenericTypes(context); + } + } } } \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs index a417b9d33..cd13d6761 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using AsmResolver.DotNet; using AsmResolver.DotNet.Signatures; +using WindowsRuntime.InteropGenerator.Discovery; using WindowsRuntime.InteropGenerator.Errors; using WindowsRuntime.InteropGenerator.Models; using WindowsRuntime.InteropGenerator.References; @@ -155,31 +156,7 @@ private static void DiscoverTypeHierarchyTypes( { args.Token.ThrowIfCancellationRequested(); - // We only care about projected Windows Runtime classes - if (!type.IsProjectedWindowsRuntimeClassType) - { - continue; - } - - // Ignore types that don't have another base class - if (type.BaseType is null || SignatureComparer.IgnoreVersion.Equals(type.BaseType, module.CorLibTypeFactory.Object)) - { - continue; - } - - // We need to resolve the base type to be able to look up attributes on it - if (!type.BaseType.IsFullyResolvable(out TypeDefinition? baseType)) - { - WellKnownInteropExceptions.WindowsRuntimeClassTypeNotResolvedWarning(type.BaseType, type).LogOrThrow(args.TreatWarningsAsErrors); - - continue; - } - - // If the base type is also a projected Windows Runtime type, track it - if (baseType.IsProjectedWindowsRuntimeType) - { - discoveryState.TrackTypeHierarchyEntry(type.FullName, baseType.FullName); - } + InteropTypeDiscovery.TryTrackTypeHierarchyType(type, args, discoveryState); } } catch (Exception e) @@ -210,120 +187,13 @@ private static void DiscoverExposedUserDefinedTypes( { args.Token.ThrowIfCancellationRequested(); - // Ignore all type definitions with generic parameters, because they would be - // unconstructed (by definition). We'll process instantiations that we can see - // separately in the discovery phase, same as we do for constructed interfaces. - if (type.HasGenericParameters) - { - continue; - } - - // We can skip all projected Windows Runtime types early, as they don't need CCW support - if (type.IsProjectedWindowsRuntimeType) - { - continue; - } - - // We'll need to look up attributes and enumerate interfaces across the entire type - // hierarchy for this type, so make sure that we can resolve all types from it first. - if (!type.IsTypeHierarchyFullyResolvable(out ITypeDefOrRef? failedResolutionBaseType)) - { - WellKnownInteropExceptions.UserDefinedTypeNotFullyResolvedWarning(failedResolutionBaseType, type).LogOrThrow(args.TreatWarningsAsErrors); - - continue; - } - - // We only want to process non-generic user-defined types that are potentially exposed to Windows Runtime - if (!type.IsPossiblyWindowsRuntimeExposedType || type.IsWindowsRuntimeManagedOnlyType(interopReferences)) - { - continue; - } - - // Since we're reusing the builder for all types, make sure to clear it first - interfaces.Clear(); - - // We want to explicitly track whether the type implements any projected Windows Runtime - // interfaces, as we are only interested in such types. We want to also gather all - // implemented '[GeneratedComInterface]' interfaces, but if a type only implements - // those, we will ignore it. Such types should be marshalled via 'ComWrappers' directly. - bool hasAnyProjectedWindowsRuntimeInterfaces = false; - - // Gather all implemented Windows Runtime interfaces for the current type - foreach (InterfaceImplementation implementation in type.EnumerateAllInterfaces()) - { - // If the current implementation has no valid interface, skip it. - // This should never really happen for valid .NET assemblies. - if (implementation.Interface?.ToReferenceTypeSignature() is not TypeSignature interfaceSignature) - { - continue; - } - - // Check for projected Windows Runtime interfaces first - if (interfaceSignature.IsWindowsRuntimeType(interopReferences)) - { - // Make sure we can resolve the interface type fully, which we should always be able to do. - // This can really only fail for some constructed generics, for invalid type arguments. - if (!interfaceSignature.IsFullyResolvable(out _)) - { - WellKnownInteropExceptions.WindowsRuntimeInterfaceTypeNotResolvedWarning(interfaceSignature, type).LogOrThrow(args.TreatWarningsAsErrors); - - continue; - } - - hasAnyProjectedWindowsRuntimeInterfaces = true; - - interfaces.Add(interfaceSignature); - } - else if (implementation.Interface.IsGeneratedComInterfaceType) - { - // To properly track '[GeneratedComInterface]' implementations, we need to be able to resolve those interface types - if (!implementation.Interface.IsFullyResolvable(out TypeDefinition? interfaceDefinition)) - { - WellKnownInteropExceptions.GeneratedComInterfaceTypeNotResolvedWarning(interfaceSignature, type).LogOrThrow(args.TreatWarningsAsErrors); - - continue; - } - - // We can only gather this type if we can find the generated 'InterfaceInformation' type. - // If we can't find it, we can't add the interface to the list of interface entries. We - // should warn if that's the (unlikely) case, so users can at least know that something - // is wrong. Otherwise we'd just silently ignore these types, resulting in runtime failures. - if (!interfaceDefinition.TryGetInterfaceInformationType(interopReferences, out _)) - { - WellKnownInteropExceptions.GeneratedComInterfaceImplementationTypeNotFoundWarning(interfaceDefinition, type).LogOrThrow(args.TreatWarningsAsErrors); - - continue; - } - - // Ensure we can get the '[GuidAttribute]' from the interface. We need this at compile time - // so we can check against some specific IID which might affect how we construct the COM - // interface entries. For instance, we need to check whether 'IMarshal' is implemented. - if (!interfaceDefinition.TryGetGuidAttribute(interopReferences, out Guid iid)) - { - WellKnownInteropExceptions.GeneratedComInterfaceGuidAttributeNotFoundWarning(interfaceDefinition, type).LogOrThrow(args.TreatWarningsAsErrors); - - continue; - } - - // Validate that the current interface isn't trying to implement a reserved interface. - // For instance, it's not allowed to try to explicitly implement 'IUnknown' or 'IInspectable'. - if (WellKnownInterfaceIIDs.ReservedIIDsMap.TryGetValue(iid, out string? interfaceName)) - { - throw WellKnownInteropExceptions.GeneratedComInterfaceReservedGuidError(interfaceDefinition, type, iid, interfaceName); - } - - // Also track all '[GeneratedComInterface]' interfaces too, and filter them later (below) - interfaces.Add(interfaceSignature); - } - } - - // If the user-defined type doesn't implement any Windows Runtime interfaces, it's not considered exposed - if (!hasAnyProjectedWindowsRuntimeInterfaces) - { - continue; - } - - discoveryState.TrackUserDefinedType(type.ToTypeSignature(), interfaces.ToEquatableSet()); + // Track the type (if it's not applicable, it will be a no-op) + InteropTypeDiscovery.TryTrackExposedUserDefinedType( + typeDefinition: type, + typeSignature: type.ToTypeSignature(), + args: args, + discoveryState: discoveryState, + interopReferences: interopReferences); } } catch (Exception e) @@ -358,85 +228,13 @@ private static void DiscoverGenericTypeInstantiations( continue; } - // Ignore types that are not fully resolvable (this likely means a .dll is missing) - if (!typeSignature.IsFullyResolvable(out TypeDefinition? typeDefinition)) - { - // Log a warning the first time we fail to resolve this generic instantiation in this module - if (discoveryState.TrackFailedResolutionType(typeSignature, module)) - { - WellKnownInteropExceptions.GenericTypeSignatureNotResolvedError(typeSignature, module).LogOrThrow(args.TreatWarningsAsErrors); - } - - continue; - } - - // Check for all '[ReadOnly]Span' types in particular, and track them as SZ array types. - // This is because "pass-array" and "fill-array" parameters are projected using spans, but - // those projections require the marshalling code produced when discovering SZ array types. - // So if we see any of these spans where the element type is a Windows Runtime type, we - // manually construct an SZ array type for it and add it to the set of tracked array types. - if (typeSignature.IsValueType && - typeSignature.IsConstructedSpanOrReadOnlySpanType(interopReferences) && - typeSignature.TypeArguments[0].IsWindowsRuntimeType(interopReferences)) - { - discoveryState.TrackSzArrayType(typeSignature.TypeArguments[0].MakeSzArrayType()); - - continue; - } - - // Ignore generic instantiations that are not Windows Runtime types. That is, those that - // have a generic type definition that's not a Windows Runtime type, or that have any type - // arguments that are not Windows Runtime types. - if (!typeSignature.IsWindowsRuntimeType(interopReferences)) - { - continue; - } - - // Gather all 'KeyValuePair<,>' instances - if (typeSignature.IsValueType && typeSignature.IsConstructedKeyValuePairType(interopReferences)) - { - discoveryState.TrackKeyValuePairType(typeSignature); - - continue; - } - - // Gather all Windows Runtime delegate types. We want to gather all projected delegate types, plus - // any custom-mapped ones (e.g. 'EventHandler' and 'EventHandler'). - // The filtering is already done above, so here we can rely the type will be of one of those kinds. - if (typeDefinition.IsDelegate) - { - discoveryState.TrackGenericDelegateType(typeSignature); - - continue; - } - - // Track all projected Windows Runtime generic interfaces - if (typeDefinition.IsInterface) - { - discoveryState.TrackGenericInterfaceType(typeSignature, interopReferences); - - // We also want to crawl base interfaces - foreach (GenericInstanceTypeSignature interfaceSignature in typeDefinition.EnumerateGenericInstanceInterfaceSignatures(typeSignature)) - { - if (!interfaceSignature.IsFullyResolvable(out _)) - { - // Also log a warning the first time we fail to resolve one of the recursively discovered generic - // instantiations from this module. The enumeration also yields back interfaces that couldn't be - // resolved, as that step is performed after yielding. This is done so we can have our own logic - // to log warnings or throw errors from here while we're processing interfaces in this module. - if (discoveryState.TrackFailedResolutionType(interfaceSignature, module)) - { - WellKnownInteropExceptions.GenericTypeSignatureNotResolvedError(interfaceSignature, module).LogOrThrow(args.TreatWarningsAsErrors); - } - - continue; - } - - discoveryState.TrackGenericInterfaceType(interfaceSignature, interopReferences); - } - - continue; - } + // Track the constructed generic type (if it's not applicable, it will be a no-op) + InteropTypeDiscovery.TryTrackGenericTypeInstance( + typeSignature: typeSignature, + args: args, + discoveryState: discoveryState, + interopReferences: interopReferences, + module: module); } } catch (Exception e) @@ -471,26 +269,13 @@ private static void DiscoverSzArrayTypes( continue; } - // Ignore types that are not fully resolvable (this likely means a .dll is missing) - if (!typeSignature.IsFullyResolvable(out _)) - { - // Log a warning the first time we fail to resolve this SZ array in this module - if (discoveryState.TrackFailedResolutionType(typeSignature, module)) - { - WellKnownInteropExceptions.SzArrayTypeSignatureNotResolvedError(typeSignature, module).LogOrThrow(args.TreatWarningsAsErrors); - } - - continue; - } - - // Ignore array types that are not Windows Runtime types - if (!typeSignature.IsWindowsRuntimeType(interopReferences)) - { - continue; - } - - // Track all SZ array types, as we'll need to emit marshalling code for them - discoveryState.TrackSzArrayType(typeSignature); + // Track the SZ array type (if it's not applicable, it will be a no-op) + InteropTypeDiscovery.TryTrackSzArrayType( + typeSignature: typeSignature, + args: args, + discoveryState: discoveryState, + interopReferences: interopReferences, + module: module); } } catch (Exception e) diff --git a/src/WinRT.Interop.Generator/Helpers/TypeExclusions.cs b/src/WinRT.Interop.Generator/Helpers/TypeExclusions.cs new file mode 100644 index 000000000..74b5ab799 --- /dev/null +++ b/src/WinRT.Interop.Generator/Helpers/TypeExclusions.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using AsmResolver.DotNet; +using AsmResolver.DotNet.Signatures; +using WindowsRuntime.InteropGenerator.References; + +namespace WindowsRuntime.InteropGenerator.Helpers; + +/// +/// Contains logic to handle special-case types to exclude from the interop API surface. +/// +internal static class TypeExclusions +{ + /// + /// Checks whether a given type should be excluded from the interop API surface. + /// + /// The type to check. + /// The instance to use. + /// Whether should be excluded from the interop API surface. + public static bool IsExcluded(ITypeDescriptor type, InteropReferences interopReferences) + { + // If we have a constructed generic type, extract the generic type definition + // and use that for checking. We don't have exclusion logic for type arguments. + if (type is GenericInstanceTypeSignature typeSignature) + { + return IsExcluded(typeSignature.GenericType, interopReferences); + } + + // Also handle SZ arrays and check their element type + if (type is SzArrayTypeSignature arraySignature) + { + return IsExcluded(arraySignature.BaseType, interopReferences); + } + + // This is the full set of types we want to always exclude from marshalling. + // We can't put this in a global variable as we need the 'InteropReferences' + // instance to actually retrieve the type references to enumerate. However + // by just using a 'ReadOnlySpan' here, the full list is stack-allocated. + ReadOnlySpan excludedTypes = + [ + interopReferences.Task1, + interopReferences.ConditionalWeakTable2 + ]; + + // Check if the input type matches any of our exclusions + return excludedTypes.Contains(type, SignatureComparer.IgnoreVersion); + } +} diff --git a/src/WinRT.Interop.Generator/References/InteropReferences.cs b/src/WinRT.Interop.Generator/References/InteropReferences.cs index 348103964..36bc0b02b 100644 --- a/src/WinRT.Interop.Generator/References/InteropReferences.cs +++ b/src/WinRT.Interop.Generator/References/InteropReferences.cs @@ -193,6 +193,11 @@ public InteropReferences( /// public GenericInstanceTypeSignature ReadOnlySpanInt32 => field ??= ReadOnlySpan1.MakeGenericValueType(_corLibTypeFactory.Int32); + /// + /// Gets the for . + /// + public TypeReference Task1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Threading.Tasks"u8, "Task`1"u8); + /// /// Gets the for . /// diff --git a/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncAction.cs b/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncAction.cs index 03cdcf9c8..b6720c55f 100644 --- a/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncAction.cs +++ b/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncAction.cs @@ -14,6 +14,7 @@ namespace WindowsRuntime; /// The implementation of a native object for . /// /// +[WindowsRuntimeManagedOnlyType] internal sealed class WindowsRuntimeAsyncAction : WindowsRuntimeObject, IAsyncAction, IWindowsRuntimeInterface, diff --git a/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncActionWithProgress{TProgress}.cs b/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncActionWithProgress{TProgress}.cs index 31213b8ba..7f192a974 100644 --- a/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncActionWithProgress{TProgress}.cs +++ b/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncActionWithProgress{TProgress}.cs @@ -17,6 +17,7 @@ namespace WindowsRuntime; /// The type of progress information. /// The implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncOperationWithProgress{TResult, TProgress}.cs b/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncOperationWithProgress{TResult, TProgress}.cs index a9d1dd212..a24863977 100644 --- a/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncOperationWithProgress{TResult, TProgress}.cs +++ b/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncOperationWithProgress{TResult, TProgress}.cs @@ -18,6 +18,7 @@ namespace WindowsRuntime; /// The type of progress information. /// The implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncOperation{TResult}.cs b/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncOperation{TResult}.cs index 53113048a..86bdd28dc 100644 --- a/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncOperation{TResult}.cs +++ b/src/WinRT.Runtime2/AsyncInfo/WindowsRuntimeAsyncOperation{TResult}.cs @@ -17,6 +17,7 @@ namespace WindowsRuntime; /// The result type. /// The implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerable.cs b/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerable.cs index ceae5ea36..c7f81f8e8 100644 --- a/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerable.cs +++ b/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerable.cs @@ -12,6 +12,7 @@ namespace WindowsRuntime; /// The implementation of all projected Windows Runtime types. /// /// +[WindowsRuntimeManagedOnlyType] internal sealed class WindowsRuntimeEnumerable : WindowsRuntimeObject, IEnumerable, IWindowsRuntimeInterface { /// diff --git a/src/WinRT.Runtime2/Bindables/WindowsRuntimeIterator.cs b/src/WinRT.Runtime2/Bindables/WindowsRuntimeIterator.cs index e2e6c0e87..09ab26209 100644 --- a/src/WinRT.Runtime2/Bindables/WindowsRuntimeIterator.cs +++ b/src/WinRT.Runtime2/Bindables/WindowsRuntimeIterator.cs @@ -15,6 +15,7 @@ namespace WindowsRuntime; /// The implementation of all projected Windows Runtime types. /// /// +[WindowsRuntimeManagedOnlyType] internal sealed unsafe class WindowsRuntimeIterator : WindowsRuntimeObject, IEnumerator, IWindowsRuntimeInterface { /// diff --git a/src/WinRT.Runtime2/Bindables/WindowsRuntimeList.cs b/src/WinRT.Runtime2/Bindables/WindowsRuntimeList.cs index 640eb5ee4..47b275fd7 100644 --- a/src/WinRT.Runtime2/Bindables/WindowsRuntimeList.cs +++ b/src/WinRT.Runtime2/Bindables/WindowsRuntimeList.cs @@ -14,6 +14,7 @@ namespace WindowsRuntime; /// The implementation of all projected Windows Runtime types. /// /// +[WindowsRuntimeManagedOnlyType] internal sealed class WindowsRuntimeList : WindowsRuntimeObject, IList, IWindowsRuntimeInterface, diff --git a/src/WinRT.Runtime2/Collections/WindowsRuntimeDictionary{TKey, TValue}.cs b/src/WinRT.Runtime2/Collections/WindowsRuntimeDictionary{TKey, TValue}.cs index 17f4d7cf1..1f6a55a3b 100644 --- a/src/WinRT.Runtime2/Collections/WindowsRuntimeDictionary{TKey, TValue}.cs +++ b/src/WinRT.Runtime2/Collections/WindowsRuntimeDictionary{TKey, TValue}.cs @@ -21,6 +21,7 @@ namespace WindowsRuntime; /// The Windows.Foundation.Collections.IIterable<T> implementation type. /// The Windows.Foundation.Collections.IMap<K, V> implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/Collections/WindowsRuntimeEnumerable{T}.cs b/src/WinRT.Runtime2/Collections/WindowsRuntimeEnumerable{T}.cs index 0f83daeac..6b7159e39 100644 --- a/src/WinRT.Runtime2/Collections/WindowsRuntimeEnumerable{T}.cs +++ b/src/WinRT.Runtime2/Collections/WindowsRuntimeEnumerable{T}.cs @@ -17,6 +17,7 @@ namespace WindowsRuntime; /// The type of objects to enumerate. /// The Windows.Foundation.Collections.IIterable<T> implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/Collections/WindowsRuntimeEnumerator{T}.cs b/src/WinRT.Runtime2/Collections/WindowsRuntimeEnumerator{T}.cs index dfddca617..637d08e82 100644 --- a/src/WinRT.Runtime2/Collections/WindowsRuntimeEnumerator{T}.cs +++ b/src/WinRT.Runtime2/Collections/WindowsRuntimeEnumerator{T}.cs @@ -18,6 +18,7 @@ namespace WindowsRuntime; /// The type of objects to enumerate. /// The implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/Collections/WindowsRuntimeList{T}.cs b/src/WinRT.Runtime2/Collections/WindowsRuntimeList{T}.cs index 67d624505..87a49a9ef 100644 --- a/src/WinRT.Runtime2/Collections/WindowsRuntimeList{T}.cs +++ b/src/WinRT.Runtime2/Collections/WindowsRuntimeList{T}.cs @@ -21,6 +21,7 @@ namespace WindowsRuntime; /// The Windows.Foundation.Collections.IIterable<T> implementation type. /// The Windows.Foundation.Collections.IVector<T> implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/Collections/WindowsRuntimeMapChangedEventArgs{TKey}.cs b/src/WinRT.Runtime2/Collections/WindowsRuntimeMapChangedEventArgs{TKey}.cs index 09eccc3f3..fa97363bd 100644 --- a/src/WinRT.Runtime2/Collections/WindowsRuntimeMapChangedEventArgs{TKey}.cs +++ b/src/WinRT.Runtime2/Collections/WindowsRuntimeMapChangedEventArgs{TKey}.cs @@ -14,6 +14,7 @@ namespace WindowsRuntime; /// The type of keys in the map. /// The Windows.Foundation.Collections.IMapChangedEventArgs<K> implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/Collections/WindowsRuntimeObservableMap{TKey, TValue}.cs b/src/WinRT.Runtime2/Collections/WindowsRuntimeObservableMap{TKey, TValue}.cs index 79c5570ef..efa2a4a95 100644 --- a/src/WinRT.Runtime2/Collections/WindowsRuntimeObservableMap{TKey, TValue}.cs +++ b/src/WinRT.Runtime2/Collections/WindowsRuntimeObservableMap{TKey, TValue}.cs @@ -26,6 +26,7 @@ namespace WindowsRuntime; /// The Windows.Foundation.Collections.IMap<K, V> implementation type. /// The Windows.Foundation.Collections.IObservableMap<K, V> implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/Collections/WindowsRuntimeObservableVector{T}.cs b/src/WinRT.Runtime2/Collections/WindowsRuntimeObservableVector{T}.cs index c2da94849..a1df93827 100644 --- a/src/WinRT.Runtime2/Collections/WindowsRuntimeObservableVector{T}.cs +++ b/src/WinRT.Runtime2/Collections/WindowsRuntimeObservableVector{T}.cs @@ -24,6 +24,7 @@ namespace WindowsRuntime; /// The Windows.Foundation.Collections.IVector<T> implementation type. /// The Windows.Foundation.Collections.IObservableVector<T> implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/Collections/WindowsRuntimeReadOnlyDictionary{TKey, TValue}.cs b/src/WinRT.Runtime2/Collections/WindowsRuntimeReadOnlyDictionary{TKey, TValue}.cs index e2e28038e..df74e42c4 100644 --- a/src/WinRT.Runtime2/Collections/WindowsRuntimeReadOnlyDictionary{TKey, TValue}.cs +++ b/src/WinRT.Runtime2/Collections/WindowsRuntimeReadOnlyDictionary{TKey, TValue}.cs @@ -21,6 +21,7 @@ namespace WindowsRuntime; /// The Windows.Foundation.Collections.IIterable<T> implementation type. /// The Windows.Foundation.Collections.IMapView<K, V> implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/Collections/WindowsRuntimeReadOnlyList{T}.cs b/src/WinRT.Runtime2/Collections/WindowsRuntimeReadOnlyList{T}.cs index 3c1ebf79a..bf171a5de 100644 --- a/src/WinRT.Runtime2/Collections/WindowsRuntimeReadOnlyList{T}.cs +++ b/src/WinRT.Runtime2/Collections/WindowsRuntimeReadOnlyList{T}.cs @@ -19,6 +19,7 @@ namespace WindowsRuntime; /// The Windows.Foundation.Collections.IIterable<T> implementation type. /// The Windows.Foundation.Collections.IVectorView<T> implementation type. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] diff --git a/src/WinRT.Runtime2/InteropServices/ObjectReference/WindowsRuntimeObjectReference.cs b/src/WinRT.Runtime2/InteropServices/ObjectReference/WindowsRuntimeObjectReference.cs index 26bb13096..ee06ae965 100644 --- a/src/WinRT.Runtime2/InteropServices/ObjectReference/WindowsRuntimeObjectReference.cs +++ b/src/WinRT.Runtime2/InteropServices/ObjectReference/WindowsRuntimeObjectReference.cs @@ -10,6 +10,7 @@ namespace WindowsRuntime.InteropServices; /// /// A managed, low-level wrapper for a native Windows Runtime object. /// +[WindowsRuntimeManagedOnlyType] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)]