From fe321c432e0fa8a2d98b2d1518113f23d5b58419 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 23 Nov 2024 16:33:58 -0800 Subject: [PATCH 01/40] Create WinRTSuppressions.cs --- .../WinRTSuppressions.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs b/src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs new file mode 100644 index 000000000..5cbbd9b8f --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs @@ -0,0 +1,43 @@ +using Microsoft.CodeAnalysis; + +namespace WinRT.SourceGenerator; + +/// +/// A container for all instances for errors reported by analyzers in this project. +/// +public static class WinRTSuppressions +{ + /// + /// Gets a for 'IDE0300', ie. "Use collection expression for array". + /// + public static readonly SuppressionDescriptor CollectionExpressionIDE0300 = new( + id: "CsWinRT2001", + suppressedDiagnosticId: "IDE0300", + justification: + "Using collection expressions when targeting 'IEnumerable', 'ICollection', 'IList', 'IReadOnlyCollection', " + + "or 'IReadOnlyList', when the collection expression is not empty, is not AOT compatible in WinRT scenarios"); + + /// + /// Gets a for 'IDE0303', ie. "Use collection expression for Create()". + /// + public static readonly SuppressionDescriptor CollectionExpressionIDE0303 = new( + id: "CsWinRT2002", + suppressedDiagnosticId: "IDE0303", + justification: "Using collection expressions when targeting an interface type without '[CollectionBuilder]' is not AOT compatible in WinRT scenarios"); + + /// + /// Gets a for 'IDE0304', ie. "Use collection expression for builder". + /// + public static readonly SuppressionDescriptor CollectionExpressionIDE0304 = new( + id: "CsWinRT2003", + suppressedDiagnosticId: "IDE0304", + justification: "Using collection expressions when targeting an interface type without '[CollectionBuilder]' is not AOT compatible in WinRT scenarios"); + + /// + /// Gets a for 'IDE0305', ie. "Use collection expression for fluent". + /// + public static readonly SuppressionDescriptor CollectionExpressionIDE0305 = new( + id: "CsWinRT2004", + suppressedDiagnosticId: "IDE0305", + justification: "Using collection expressions when targeting an interface type without '[CollectionBuilder]' is not AOT compatible in WinRT scenarios"); +} From 3d2229c0029cd067b561eba25351691223ab330d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 23 Nov 2024 17:03:18 -0800 Subject: [PATCH 02/40] Bump Roslyn to 4.8 --- .../WinRT.SourceGenerator/WinRT.SourceGenerator.csproj | 2 +- src/Authoring/cswinmd/CsWinMD.csproj | 4 ++-- src/Tests/DiagnosticTests/DiagnosticTests.csproj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj index 875bd6d58..9455d5512 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Authoring/cswinmd/CsWinMD.csproj b/src/Authoring/cswinmd/CsWinMD.csproj index 32521a5cb..783ef7adf 100644 --- a/src/Authoring/cswinmd/CsWinMD.csproj +++ b/src/Authoring/cswinmd/CsWinMD.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/src/Tests/DiagnosticTests/DiagnosticTests.csproj b/src/Tests/DiagnosticTests/DiagnosticTests.csproj index 55a15523b..57333e536 100644 --- a/src/Tests/DiagnosticTests/DiagnosticTests.csproj +++ b/src/Tests/DiagnosticTests/DiagnosticTests.csproj @@ -10,7 +10,7 @@ - + From ee324b501013a1d83b37ea1271ae5bf1a440a900 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 23 Nov 2024 17:28:53 -0800 Subject: [PATCH 03/40] Create CollectionExpressionSuppressor.cs --- .../CollectionExpressionSuppressor.cs | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs new file mode 100644 index 000000000..e3f55b376 --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; +using WinRT.SourceGenerator; + +#nullable enable + +namespace Generator; + +/// +/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class CollectionExpressionSuppressor : DiagnosticSuppressor +{ + /// + public override ImmutableArray SupportedSuppressions => ImmutableArray.Create( + WinRTSuppressions.CollectionExpressionIDE0300, + WinRTSuppressions.CollectionExpressionIDE0303, + WinRTSuppressions.CollectionExpressionIDE0304, + WinRTSuppressions.CollectionExpressionIDE0305); + + /// + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) + { + // Try to get the syntax node matching the location of the diagnostic + if (diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan) is not CollectionExpressionSyntax syntaxNode) + { + continue; + } + + // If the collection expression has no elements, we want to keep the diagnostic + if (!syntaxNode.Elements.Any()) + { + continue; + } + + SemanticModel semanticModel = context.GetSemanticModel(syntaxNode.SyntaxTree); + + // Try to get the operation for the collection expression, skip if we can't + if (semanticModel.GetOperation(syntaxNode, context.CancellationToken) is not ICollectionExpressionOperation operation) + { + continue; + } + + // Try to suppress all supported diagnostics + if (diagnostic.Id is "IDE0300" && ShouldSuppressIDE0300(operation)) + { + context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0300, diagnostic)); + } + else if (ShouldSuppressIDE0303OrIDE0304OrIDE0305(operation, semanticModel.Compilation)) + { + SuppressionDescriptor descriptor = diagnostic.Id switch + { + "IDE0303" => WinRTSuppressions.CollectionExpressionIDE0303, + "IDE0304" => WinRTSuppressions.CollectionExpressionIDE0304, + "IDE0305" => WinRTSuppressions.CollectionExpressionIDE0305, + _ => throw new Exception($"Unsupported diagnostic id: '{diagnostic.Id}'.") + }; + + context.ReportSuppression(Suppression.Create(descriptor, diagnostic)); + } + } + } + + /// + /// Checks whether 'IDE0300' should be suppressed for a given operation. + /// + private static bool ShouldSuppressIDE0300(ICollectionExpressionOperation operation) + { + // Here we only care about well known collection interface types, which are all generic + if (operation.Type is not INamedTypeSymbol { IsGenericType: true, ConstructedFrom: { } typeSymbol }) + { + return false; + } + + return typeSymbol.SpecialType is + SpecialType.System_Collections_Generic_IEnumerable_T or + SpecialType.System_Collections_Generic_ICollection_T or + SpecialType.System_Collections_Generic_IList_T or + SpecialType.System_Collections_Generic_IReadOnlyCollection_T or + SpecialType.System_Collections_Generic_IReadOnlyList_T; + } + + /// + /// Checks whether 'IDE0303', 'IDE0304', or 'IDE0305' should be suppressed for a given operation. + /// + private static bool ShouldSuppressIDE0303OrIDE0304OrIDE0305(ICollectionExpressionOperation operation, Compilation compilation) + { + // We only possibly suppress here for some interface types + if (operation.Type is not INamedTypeSymbol { TypeKind: TypeKind.Interface } typeSymbol) + { + return false; + } + + // Get the symbol for '[CollectionBuilder]', we need it for lookups + if (compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.CollectionBuilderAttribute") is not { } collectionBuilderSymbol) + { + return false; + } + + // We should only suppress when the target interface does not have '[CollectionBuilder]' on it. + // If it does, then the CsWinRT analyzer will be able to analyze the body of the 'Create' method. + return !GeneratorHelper.HasAttributeWithType(typeSymbol, collectionBuilderSymbol); + } +} From 9e78cb95a8576e7d4d79e0d3ed1e0ed7374d4891 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 23 Nov 2024 17:44:16 -0800 Subject: [PATCH 04/40] Create CollectionExpressionAnalyzer.cs --- .../AnalyzerReleases.Shipped.md | 7 ++ .../CollectionExpressionAnalyzer.cs | 64 +++++++++++++++++++ .../CsWinRTDiagnosticStrings.Designer.cs | 18 ++++++ .../CsWinRTDiagnosticStrings.resx | 8 ++- .../WinRT.SourceGenerator/WinRTRules.cs | 7 ++ 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs diff --git a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md b/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md index 95bda0d96..657130713 100644 --- a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md +++ b/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md @@ -48,3 +48,10 @@ CsWinRT1029 | Usage | Warning | Class implements WinRT interfaces generated usin Rule ID | Category | Severity | Notes --------|----------|----------|------- CsWinRT1030 | Usage | Warning | Project needs to be updated with `true` to allow generic interface code generation. + +## Release 2.3.0 + +### New Rules +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +CsWinRT1031 | Usage | Warning | Collection expressions can only be used when statically verifiable for AOT support with WinRT. diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs new file mode 100644 index 000000000..3f65957f0 --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Operations; +using WinRT.SourceGenerator; + +#nullable enable + +namespace Generator; + +/// +/// A diagnostic analyzer to warn for collection expression that are not AOT compatible in WinRT scenarios. +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class CollectionExpressionAnalyzer : DiagnosticAnalyzer +{ + /// + public override ImmutableArray SupportedDiagnostics { get; } = [WinRTRules.NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType]; + + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(static context => + { + // Get the symbol for '[CollectionBuilder]', we need it for lookups + if (context.Compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.CollectionBuilderAttribute") is not { } collectionBuilderSymbol) + { + return; + } + + context.RegisterOperationAction(context => + { + ICollectionExpressionOperation operation = (ICollectionExpressionOperation)context.Operation; + + // We only possibly warn if the target type is an interface type + if (operation.Type is not INamedTypeSymbol { TypeKind: TypeKind.Interface } typeSymbol) + { + return; + } + + // We can also skip all cases where the collection expression is empty, those are fine + if (operation.Elements.IsEmpty) + { + return; + } + + // If the target interface type doesn't have '[CollectionBuilder]' on it, we should warn + if (!GeneratorHelper.HasAttributeWithType(typeSymbol, collectionBuilderSymbol)) + { + context.ReportDiagnostic(Diagnostic.Create( + WinRTRules.NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType, + operation.Syntax.GetLocation(), + typeSymbol)); + } + }, OperationKind.CollectionExpression); + }); + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs index 65d770159..6ed871213 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs +++ b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs @@ -465,6 +465,24 @@ internal static string NonArrayMarkedInOrOut_Text2 { } } + /// + /// Looks up a localized string similar to Collection expression not safe for WinRT. + /// + internal static string NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Brief { + get { + return ResourceManager.GetString("NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Collection expressions targeting interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, or avoid using a collection expression in this case). + /// + internal static string NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Text { + get { + return ResourceManager.GetString("NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Text", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid Interface Inherited. /// diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx index 6c1d7f141..f54c624d9 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx @@ -120,7 +120,7 @@ Class '{0}' has attribute GeneratedBindableCustomProperty but it or a parent type isn't marked partial. Type and any parent types should be marked partial to allow source generation for trimming and AOT compatibility. - + Namespace is disjoint from main (winmd) namespace @@ -292,4 +292,10 @@ Consider changing the type '{1} in the member signature to one of the following types from System.Collections.Generic: {2}. {1} and {2} will be keywords (types) from DotNet + + Collection expression not safe for WinRT + + + Collection expressions targeting interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, or avoid using a collection expression in this case) + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs b/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs index 5ab4a338f..ec6f06cc5 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs @@ -238,5 +238,12 @@ private static DiagnosticDescriptor MakeRule(string id, string title, string mes CsWinRTDiagnosticStrings.ClassImplementsOldProjection_Brief, CsWinRTDiagnosticStrings.ClassOldProjectionMultipleInstances_Text, false); + + public static DiagnosticDescriptor NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType = MakeRule( + "CsWinRT1031", + CsWinRTDiagnosticStrings.NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Brief, + CsWinRTDiagnosticStrings.NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Text, + false, + true); } } From aec1e2b7b701177276919ec3cd06fb8a0dbd9201 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 10:31:36 -0800 Subject: [PATCH 05/40] Bump Roslyn to 4.9.2 --- .../WinRT.SourceGenerator/WinRT.SourceGenerator.csproj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj index 9455d5512..c88087a73 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj @@ -22,9 +22,8 @@ - - - + + From 38c9ba1f791603b317a11cfaf63325e730acbc8d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 10:42:16 -0800 Subject: [PATCH 06/40] Update 'CollectionExpressionAnalyzer' --- .../CollectionExpressionAnalyzer.cs | 12 ++++++++++-- .../CsWinRTDiagnosticStrings.Designer.cs | 2 +- .../CsWinRTDiagnosticStrings.resx | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs index 3f65957f0..ae3aa1439 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs @@ -38,8 +38,8 @@ public override void Initialize(AnalysisContext context) { ICollectionExpressionOperation operation = (ICollectionExpressionOperation)context.Operation; - // We only possibly warn if the target type is an interface type - if (operation.Type is not INamedTypeSymbol { TypeKind: TypeKind.Interface } typeSymbol) + // We only possibly warn if the target type is a generic interface type + if (operation.Type is not INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true } typeSymbol) { return; } @@ -50,6 +50,14 @@ public override void Initialize(AnalysisContext context) return; } + // We can skip 'ICollection' and 'IList', as those guarantee to use 'List' + if (typeSymbol.ConstructedFrom.SpecialType is + SpecialType.System_Collections_Generic_ICollection_T or + SpecialType.System_Collections_Generic_IList_T) + { + return; + } + // If the target interface type doesn't have '[CollectionBuilder]' on it, we should warn if (!GeneratorHelper.HasAttributeWithType(typeSymbol, collectionBuilderSymbol)) { diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs index 6ed871213..07afc830d 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs +++ b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs @@ -475,7 +475,7 @@ internal static string NonEmptyCollectionExpressionTargetingNonBuilderInterfaceT } /// - /// Looks up a localized string similar to Collection expressions targeting interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, or avoid using a collection expression in this case). + /// Looks up a localized string similar to Collection expressions targeting non mutable interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, a mutable interface type, or avoid using a collection expression in this case). /// internal static string NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Text { get { diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx index f54c624d9..c0fff5f05 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx @@ -296,6 +296,6 @@ Collection expression not safe for WinRT - Collection expressions targeting interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, or avoid using a collection expression in this case) + Collection expressions targeting non mutable interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, a mutable interface type, or avoid using a collection expression in this case) \ No newline at end of file From a59e9f9678d39d4507008be92a3d7bc86be01ebf Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 11:16:40 -0800 Subject: [PATCH 07/40] Update AotOptimizer.cs --- .../WinRT.SourceGenerator/AotOptimizer.cs | 59 +++++++++++++++---- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs index 7a4a0b4bd..49c7ca1e4 100644 --- a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs +++ b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs @@ -5,6 +5,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -1166,7 +1167,8 @@ private static bool NeedVtableOnLookupTable(SyntaxNode node) node is AssignmentExpressionSyntax || node is VariableDeclarationSyntax || node is PropertyDeclarationSyntax || - node is ReturnStatementSyntax; + node is ReturnStatementSyntax || + node is CollectionExpressionSyntax; } private static EquatableArray GetVtableAttributesToAddOnLookupTable( @@ -1244,9 +1246,9 @@ private static EquatableArray GetVtableAttributesToAddOnLookupT AddVtableAttributesForType(context.SemanticModel.GetTypeInfo(assignment.Right), fieldSymbol.Type); } } - // Detect scenarios where the variable declaration is to a boxed or cast type during initialization. else if (context.Node is VariableDeclarationSyntax variableDeclaration) { + // Detect scenarios where the variable declaration is to a boxed or cast type during initialization. var leftSymbol = context.SemanticModel.GetSymbolInfo(variableDeclaration.Type).Symbol; if (leftSymbol is INamedTypeSymbol namedType) { @@ -1260,9 +1262,9 @@ private static EquatableArray GetVtableAttributesToAddOnLookupT } } } - // Detect scenarios where the property declaration has an initializer and is to a boxed or cast type during initialization. else if (context.Node is PropertyDeclarationSyntax propertyDeclaration) { + // Detect scenarios where the property declaration has an initializer and is to a boxed or cast type during initialization. if (propertyDeclaration.Initializer != null) { var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol; @@ -1282,10 +1284,10 @@ private static EquatableArray GetVtableAttributesToAddOnLookupT } } } - // Detect scenarios where the method or property being returned from is doing a box or cast of the type - // in the return statement. - else if (context.Node is ReturnStatementSyntax returnDeclaration && returnDeclaration.Expression is not null) + else if (context.Node is ReturnStatementSyntax { Expression: not null } returnDeclaration) { + // Detect scenarios where the method or property being returned from is doing a box or cast of the type + // in the return statement. var returnSymbol = context.SemanticModel.GetTypeInfo(returnDeclaration.Expression); var parent = returnDeclaration.Ancestors().OfType().FirstOrDefault(); if (parent is MethodDeclarationSyntax methodDeclaration) @@ -1305,18 +1307,53 @@ private static EquatableArray GetVtableAttributesToAddOnLookupT } } } + else if (context.Node is CollectionExpressionSyntax collectionExpression) + { + // Detect collection expressions scenarios targeting interfaces, where we can rely on the concrete type + if (context.SemanticModel.GetOperation(collectionExpression) is ICollectionExpressionOperation operation && + operation.Type is INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true, IsUnboundGenericType: false, ConstructedFrom: not null } collectionType) + { + // Case 1: empty collection expression targeting 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList'. + // In this case, we can rely on Roslyn using an empty array. So let's pretend we saw it, and gather it for lookups. + if (operation.Elements.IsEmpty && + collectionType.ConstructedFrom.SpecialType is + SpecialType.System_Collections_Generic_IEnumerable_T or + SpecialType.System_Collections_Generic_IReadOnlyCollection_T or + SpecialType.System_Collections_Generic_IReadOnlyList_T) + { + IArrayTypeSymbol arrayTypeSymbol = context.SemanticModel.Compilation.CreateArrayTypeSymbol(collectionType.TypeArguments[0], rank: 1); + + AddVtableAttributesForTypeDirect(arrayTypeSymbol, null, collectionType); + } + else if (collectionType.ConstructedFrom.SpecialType is SpecialType.System_Collections_Generic_ICollection_T or SpecialType.System_Collections_Generic_IList_T) + { + // Case 2: a collection expression (empty or not) targeting 'ICollection' or 'IList'. + // In this case, Roslyn guarantees that 'List' will be used, so we can gather that type. + INamedTypeSymbol listOfTSymbol = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Collections.Generic.List`1")!; + INamedTypeSymbol constructedListSymbol = listOfTSymbol.Construct(collectionType.TypeArguments[0]); + + AddVtableAttributesForTypeDirect(constructedListSymbol, null, collectionType); + } + } + } return vtableAttributes.ToImmutableArray(); + // Helper to directly use 'AddVtableAttributesForTypeDirect' with 'TypeInfo' values + void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType, ITypeSymbol convertedToTypeSymbol) + { + AddVtableAttributesForTypeDirect(instantiatedType.Type, instantiatedType.ConvertedType, convertedToTypeSymbol); + } + // This handles adding vtable information for types for which we can not directly put an attribute on them. // This includes generic types that are boxed and and non-WinRT types for which our AOT source generator hasn't // ran on but implements WinRT interfaces. - void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType, ITypeSymbol convertedToTypeSymbol) + void AddVtableAttributesForTypeDirect(ITypeSymbol instantiatedTypeSymbol, ITypeSymbol instantiatedConvertedTypeSymbol, ITypeSymbol convertedToTypeSymbol) { // This handles the case where there is an WinRT array possibly being assigned // to an object type or a list. In this case, the IList interfaces of the array // type need to be put on the CCW. - if (instantiatedType.Type is IArrayTypeSymbol arrayType) + if (instantiatedTypeSymbol is IArrayTypeSymbol arrayType) { if (convertedToTypeSymbol is not IArrayTypeSymbol && // Make sure we aren't just assigning it to a value type such as ReadOnlySpan @@ -1338,10 +1375,10 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType AddEnumeratorAdapterForType(arrayType.ElementType, typeMapper, context.SemanticModel.Compilation, isManagedOnlyType, isWinRTType, vtableAttributes); } } - else if (instantiatedType.Type is not null || instantiatedType.ConvertedType is not null) + else if (instantiatedTypeSymbol is not null || instantiatedConvertedTypeSymbol is not null) { // Type might be null such as for lambdas, so check converted type in that case. - var instantiatedTypeSymbol = instantiatedType.Type ?? instantiatedType.ConvertedType; + instantiatedTypeSymbol ??= instantiatedConvertedTypeSymbol; if (visitedTypes.Contains(instantiatedTypeSymbol)) { @@ -1386,7 +1423,7 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType // If the type is defined in the same assembly as what the source generator is running on, // we let the WinRTExposedType attribute generator handle it. The only scenario the generator // doesn't handle which we handle here is if it is a generic type implementing generic WinRT interfaces. - (!SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) || + (!SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) || GeneratorHelper.HasNonInstantiatedWinRTGeneric(instantiatedTypeSymbol.OriginalDefinition, typeMapper)) && // Make sure the type we are passing is being boxed or cast to another interface. !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol); From 38075b33ec6131c5ae2f7e4996acb99351df0610 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 11:50:55 -0800 Subject: [PATCH 08/40] Create CollectionExpressionIDE0300Suppressor.cs --- .../CollectionExpressionIDE0300Suppressor.cs | 80 +++++++++++++++++++ .../CollectionExpressionSuppressor.cs | 33 ++------ 2 files changed, 85 insertions(+), 28 deletions(-) create mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs new file mode 100644 index 000000000..146be1f6f --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using WinRT.SourceGenerator; + +#nullable enable + +namespace Generator; + +/// +/// +/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. +/// +/// +/// This analyzer suppress diagnostics for cases like these: +/// +/// int[] a = { 1, 2, 3 }; +/// int[] b = new[] { 1, 2, 3 }; +/// int[] c = new int[] { 1, 2, 3 }; +/// +/// +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class CollectionExpressionIDE0300Suppressor : DiagnosticSuppressor +{ + /// + public override ImmutableArray SupportedSuppressions { get; } = [WinRTSuppressions.CollectionExpressionIDE0300]; + + /// + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) + { + // Try to get the syntax node matching the location of the diagnostic + SyntaxNode? syntaxNode = diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); + + // We only support 3 types of expressions here: + // Array initializer expressions: '{ 1, 2, 3 }' + // Implicit array creation expressions: 'new[] { 1, 2, 3 }' + // Array creation expressions: 'new int[] { 1, 2, 3 }' + if (syntaxNode?.Kind() is not (SyntaxKind.ArrayInitializerExpression or SyntaxKind.ImplicitArrayCreationExpression or SyntaxKind.ArrayCreationExpression)) + { + continue; + } + + // If the collection expression has no elements, we want to keep the diagnostic. That is + // because fixing the diagnostic (ie. switching to a collection expression) would be safe. + if (syntaxNode is + InitializerExpressionSyntax { Expressions: [] } or + ImplicitArrayCreationExpressionSyntax { Initializer.Expressions: [] } or + ArrayCreationExpressionSyntax { Initializer.Expressions: [] }) + { + continue; + } + + Microsoft.CodeAnalysis.TypeInfo typeInfo = context.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode, context.CancellationToken); + + // We might only opportunistically suppress the diagnostic when assigning to a generic interface type + if (typeInfo.ConvertedType is not INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true, IsUnboundGenericType: false } typeSymbol) + { + continue; + } + + // If the target type is either 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList', suppress the diagnostic. + // This is because using a collection expression in this case would produce an opaque type we cannot analyze for marshalling. + if (typeSymbol.SpecialType is + SpecialType.System_Collections_Generic_IEnumerable_T or + SpecialType.System_Collections_Generic_IReadOnlyCollection_T or + SpecialType.System_Collections_Generic_IReadOnlyList_T) + { + context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0300, diagnostic)); + } + } + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs index e3f55b376..e94469253 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Operations; using WinRT.SourceGenerator; @@ -21,11 +20,12 @@ namespace Generator; public sealed class CollectionExpressionSuppressor : DiagnosticSuppressor { /// - public override ImmutableArray SupportedSuppressions => ImmutableArray.Create( - WinRTSuppressions.CollectionExpressionIDE0300, + public override ImmutableArray SupportedSuppressions { get; } = + [ WinRTSuppressions.CollectionExpressionIDE0303, WinRTSuppressions.CollectionExpressionIDE0304, - WinRTSuppressions.CollectionExpressionIDE0305); + WinRTSuppressions.CollectionExpressionIDE0305 + ]; /// public override void ReportSuppressions(SuppressionAnalysisContext context) @@ -53,11 +53,7 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) } // Try to suppress all supported diagnostics - if (diagnostic.Id is "IDE0300" && ShouldSuppressIDE0300(operation)) - { - context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0300, diagnostic)); - } - else if (ShouldSuppressIDE0303OrIDE0304OrIDE0305(operation, semanticModel.Compilation)) + if (ShouldSuppressIDE0303OrIDE0304OrIDE0305(operation, semanticModel.Compilation)) { SuppressionDescriptor descriptor = diagnostic.Id switch { @@ -72,25 +68,6 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) } } - /// - /// Checks whether 'IDE0300' should be suppressed for a given operation. - /// - private static bool ShouldSuppressIDE0300(ICollectionExpressionOperation operation) - { - // Here we only care about well known collection interface types, which are all generic - if (operation.Type is not INamedTypeSymbol { IsGenericType: true, ConstructedFrom: { } typeSymbol }) - { - return false; - } - - return typeSymbol.SpecialType is - SpecialType.System_Collections_Generic_IEnumerable_T or - SpecialType.System_Collections_Generic_ICollection_T or - SpecialType.System_Collections_Generic_IList_T or - SpecialType.System_Collections_Generic_IReadOnlyCollection_T or - SpecialType.System_Collections_Generic_IReadOnlyList_T; - } - /// /// Checks whether 'IDE0303', 'IDE0304', or 'IDE0305' should be suppressed for a given operation. /// From cd139de4eaae08d81726db6be2276f877b1f8590 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 12:33:29 -0800 Subject: [PATCH 09/40] Create CollectionExpressionIDE0305Suppressor.cs --- .../CollectionExpressionIDE0305Suppressor.cs | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs new file mode 100644 index 000000000..4785eea6c --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.CSharp; +using WinRT.SourceGenerator; + +#nullable enable + +namespace Generator; + +/// +/// +/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. +/// +/// +/// This analyzer suppress diagnostics for cases like these: +/// +/// List i = new[] { 1, 2, 3 }.ToList(); +/// IEnumerable j = new[] { 1, 2, 3 }.ToList(); +/// +/// +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class CollectionExpressionIDE0305Suppressor : DiagnosticSuppressor +{ + /// + public override ImmutableArray SupportedSuppressions { get; } = [WinRTSuppressions.CollectionExpressionIDE0305]; + + /// + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) + { + // Try to get the syntax node matching the location of the diagnostic + SyntaxNode? syntaxNode = diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); + + // We expect to have found an invocation expression (eg. 'ToList()') + if (syntaxNode?.Kind() is not SyntaxKind.InvocationExpression) + { + continue; + } + + Microsoft.CodeAnalysis.TypeInfo typeInfo = context.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode, context.CancellationToken); + + // We only want to suppress this diagnostic when the result of the invocation is assigned to an unsupported interface type + if (typeInfo.ConvertedType is not INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true, IsUnboundGenericType: false } typeSymbol) + { + continue; + } + + // Like for 'IDE0300', suppress diagnostics for 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList' + if (typeSymbol.SpecialType is + SpecialType.System_Collections_Generic_IEnumerable_T or + SpecialType.System_Collections_Generic_IReadOnlyCollection_T or + SpecialType.System_Collections_Generic_IReadOnlyList_T) + { + context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0305, diagnostic)); + } + } + } +} From 99d1eac687296d7d327f1b4d9e0a7df1f1aab4bf Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 12:37:47 -0800 Subject: [PATCH 10/40] Create CollectionExpressionIDE0303Suppressor.cs --- .../CollectionExpressionIDE0303Suppressor.cs | 42 ++++++++++++++++ .../CollectionExpressionIDE0305Suppressor.cs | 49 +++++++++++-------- 2 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs new file mode 100644 index 000000000..aa64a5786 --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using WinRT.SourceGenerator; + +#nullable enable + +namespace Generator; + +/// +/// +/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. +/// +/// +/// This analyzer suppress diagnostics for cases like these: +/// +/// ImmutableArray i = ImmutableArray.Create(1, 2, 3); +/// IEnumerable j = ImmutableArray.Create(1, 2, 3); +/// +/// +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class CollectionExpressionIDE0303Suppressor : DiagnosticSuppressor +{ + /// + public override ImmutableArray SupportedSuppressions { get; } = [WinRTSuppressions.CollectionExpressionIDE0303]; + + /// + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) + { + if (CollectionExpressionIDE0305Suppressor.IsInvocationAssignedToUnsupportedInterfaceType(context, diagnostic)) + { + context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0303, diagnostic)); + } + } + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs index 4785eea6c..5cbf8c2d6 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs @@ -34,31 +34,40 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) { foreach (Diagnostic diagnostic in context.ReportedDiagnostics) { - // Try to get the syntax node matching the location of the diagnostic - SyntaxNode? syntaxNode = diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); - - // We expect to have found an invocation expression (eg. 'ToList()') - if (syntaxNode?.Kind() is not SyntaxKind.InvocationExpression) + if (IsInvocationAssignedToUnsupportedInterfaceType(context, diagnostic)) { - continue; + context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0305, diagnostic)); } + } + } - Microsoft.CodeAnalysis.TypeInfo typeInfo = context.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode, context.CancellationToken); + /// + /// Checks whether a given diagnostic is over an invocation assigning to an unsupported interface type. + /// + public static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAnalysisContext context, Diagnostic diagnostic) + { + // Try to get the syntax node matching the location of the diagnostic + SyntaxNode? syntaxNode = diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); - // We only want to suppress this diagnostic when the result of the invocation is assigned to an unsupported interface type - if (typeInfo.ConvertedType is not INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true, IsUnboundGenericType: false } typeSymbol) - { - continue; - } + // We expect to have found an invocation expression (eg. 'ToList()') + if (syntaxNode?.Kind() is not SyntaxKind.InvocationExpression) + { + return false; + } - // Like for 'IDE0300', suppress diagnostics for 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList' - if (typeSymbol.SpecialType is - SpecialType.System_Collections_Generic_IEnumerable_T or - SpecialType.System_Collections_Generic_IReadOnlyCollection_T or - SpecialType.System_Collections_Generic_IReadOnlyList_T) - { - context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0305, diagnostic)); - } + Microsoft.CodeAnalysis.TypeInfo typeInfo = context.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode, context.CancellationToken); + + // We only want to suppress this diagnostic when the result of the invocation is assigned to an unsupported interface type + if (typeInfo.ConvertedType is not INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true, IsUnboundGenericType: false } typeSymbol) + { + return false; } + + // Like for 'IDE0300', suppress diagnostics for 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList' + return + typeSymbol.SpecialType is + SpecialType.System_Collections_Generic_IEnumerable_T or + SpecialType.System_Collections_Generic_IReadOnlyCollection_T or + SpecialType.System_Collections_Generic_IReadOnlyList_T; } } From 209ef7c2817167c05a8417c755c4659deed16369 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 12:40:26 -0800 Subject: [PATCH 11/40] Add 'SourceGeneratorTest' project --- .../SourceGeneratorTest.csproj | 14 ++++++++++++++ src/cswinrt.sln | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj diff --git a/src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj b/src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj new file mode 100644 index 000000000..2a417520c --- /dev/null +++ b/src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj @@ -0,0 +1,14 @@ + + + net8.0 + + + + + + + + + + + diff --git a/src/cswinrt.sln b/src/cswinrt.sln index f74d6d53b..60f7a8a86 100644 --- a/src/cswinrt.sln +++ b/src/cswinrt.sln @@ -174,6 +174,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NonWinRT", "Tests\Functiona EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OptInMode", "Tests\FunctionalTests\OptInMode\OptInMode.csproj", "{FFC0B06E-78E7-44D5-8E67-8FE5744CE071}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGeneratorTest", "Tests\UnitTest\SourceGeneratorTest\SourceGeneratorTest.csproj", "{CB7C338F-3850-4744-A1EA-3DC47B703C4A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -842,6 +844,22 @@ Global {FFC0B06E-78E7-44D5-8E67-8FE5744CE071}.Release|x64.Build.0 = Release|x64 {FFC0B06E-78E7-44D5-8E67-8FE5744CE071}.Release|x86.ActiveCfg = Release|x86 {FFC0B06E-78E7-44D5-8E67-8FE5744CE071}.Release|x86.Build.0 = Release|x86 + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Debug|ARM.Build.0 = Debug|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Debug|ARM64.Build.0 = Debug|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Debug|x64.ActiveCfg = Debug|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Debug|x64.Build.0 = Debug|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Debug|x86.ActiveCfg = Debug|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Debug|x86.Build.0 = Debug|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|ARM.ActiveCfg = Release|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|ARM.Build.0 = Release|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|ARM64.ActiveCfg = Release|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|ARM64.Build.0 = Release|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|x64.ActiveCfg = Release|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|x64.Build.0 = Release|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|x86.ActiveCfg = Release|Any CPU + {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -894,6 +912,7 @@ Global {30EE902C-C1D3-40E0-B63C-59FFB4503633} = {5ECC38F0-16FD-47E1-B8DC-8C474008AD55} {54D6C10E-19C9-4BCF-B237-682C0120FC1F} = {5ECC38F0-16FD-47E1-B8DC-8C474008AD55} {FFC0B06E-78E7-44D5-8E67-8FE5744CE071} = {5ECC38F0-16FD-47E1-B8DC-8C474008AD55} + {CB7C338F-3850-4744-A1EA-3DC47B703C4A} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5AE8C9D7-2613-4E1A-A4F2-579BAC28D0A2} From 6870388a0e567025cf899776faa8e160acf50802 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 12:59:20 -0800 Subject: [PATCH 12/40] Add tests for 'CollectionExpressionAnalyzer' --- .../DiagnosticAnalyzerTests.cs | 152 ++++++++++++++++++ ...lyzerWithLanguageVersionTest{TAnalyzer}.cs | 69 ++++++++ .../SourceGeneratorTest.csproj | 5 + 3 files changed, 226 insertions(+) create mode 100644 src/Tests/UnitTest/SourceGeneratorTest/DiagnosticAnalyzerTests.cs create mode 100644 src/Tests/UnitTest/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs diff --git a/src/Tests/UnitTest/SourceGeneratorTest/DiagnosticAnalyzerTests.cs b/src/Tests/UnitTest/SourceGeneratorTest/DiagnosticAnalyzerTests.cs new file mode 100644 index 000000000..28fc1a484 --- /dev/null +++ b/src/Tests/UnitTest/SourceGeneratorTest/DiagnosticAnalyzerTests.cs @@ -0,0 +1,152 @@ +using System.Threading.Tasks; +using Generator; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SourceGeneratorTest.Helpers; + +namespace SourceGeneratorTest; + +[TestClass] +public class DiagnosticAnalyzerTests +{ + [TestMethod] + public async Task CollectionExpression_TargetingConcreteType_DoesNotWarn() + { + const string source = """ + using System.Collections.Generic; + + class Test + { + void M() + { + List a = []; + List b = [1, 2, 3]; + int[] c = []; + int[] d = [1, 2, 3]; + } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + } + + [TestMethod] + public async Task CollectionExpression_TargetingInterface_Empty_DoesNotWarn() + { + const string source = """ + using System.Collections.Generic; + + class Test + { + void M() + { + IEnumerable a = []; + ICollection b = []; + IReadOnlyCollection c = []; + IList d = []; + IReadOnlyList e = []; + } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + } + + [TestMethod] + public async Task CollectionExpression_TargetingInterface_Mutable_NotEmpty_DoesNotWarn() + { + const string source = """ + using System.Collections.Generic; + + class Test + { + void M(int x, IEnumerable y) + { + ICollection a = [1, 2, 3]; + ICollection b = [x]; + ICollection c = [1, x, ..y]; + IList d = [1, 2, 3]; + IList e = [x]; + IList f = [1, x, ..y]; + } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + } + + [TestMethod] + public async Task CollectionExpression_TargetingInterface_WithCollectionBuilder_DoesNotWarn() + { + const string source = """ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + + class Test + { + void M(int x, IEnumerable y) + { + IMyInterface a = []; + IMyInterface b = [1, 2, 3]; + IMyInterface c = [x]; + IMyInterface d = [1, x, ..y]; + } + } + + [CollectionBuilder(typeof(MyInterfaceBuilder), nameof(MyInterfaceBuilder.Create))] + interface IMyInterface : IEnumerable + { + } + + class MyInterface : IMyInterface + { + public IEnumerator GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + } + + class MyInterfaceBuilder + { + public static IMyInterface Create(ReadOnlySpan span) + { + return new MyInterface(); + } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + } + + [TestMethod] + public async Task CollectionExpression_TargetingInterface_ReadOnly_NotEmpty_Warns() + { + const string source = """ + using System.Collections.Generic; + + class Test + { + void M(int x, IEnumerable y) + { + IEnumerable a = {|CsWinRT1031:[1, 2, 3]|}; + IEnumerable b = {|CsWinRT1031:[x]|}; + IEnumerable c = {|CsWinRT1031:[1, x, ..y]|}; + IReadOnlyCollection d = {|CsWinRT1031:[1, 2, 3]|}; + IReadOnlyCollection e = {|CsWinRT1031:[x]|}; + IReadOnlyCollection f = {|CsWinRT1031:[1, x, ..y]|}; + IReadOnlyList g = {|CsWinRT1031:[1, 2, 3]|}; + IReadOnlyList h = {|CsWinRT1031:[x]|}; + IReadOnlyList i = {|CsWinRT1031:[1, x, ..y]|}; + } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + } +} \ No newline at end of file diff --git a/src/Tests/UnitTest/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs b/src/Tests/UnitTest/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs new file mode 100644 index 000000000..42ba5b72f --- /dev/null +++ b/src/Tests/UnitTest/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs @@ -0,0 +1,69 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis; +using WinRT; + +namespace SourceGeneratorTest.Helpers; + +/// +/// A custom that uses a specific C# language version to parse code. +/// +/// The type of the analyzer to test. +// Ported from https://github.com/Sergio0694/ComputeSharp +internal sealed class CSharpAnalyzerWithLanguageVersionTest : CSharpAnalyzerTest + where TAnalyzer : DiagnosticAnalyzer, new() +{ + /// + /// Whether to enable unsafe blocks. + /// + private readonly bool _allowUnsafeBlocks; + + /// + /// The C# language version to use to parse code. + /// + private readonly LanguageVersion _languageVersion; + + /// + /// Creates a new instance with the specified paramaters. + /// + /// Whether to enable unsafe blocks. + /// The C# language version to use to parse code. + private CSharpAnalyzerWithLanguageVersionTest(bool allowUnsafeBlocks, LanguageVersion languageVersion) + { + _allowUnsafeBlocks = allowUnsafeBlocks; + _languageVersion = languageVersion; + } + + /// + protected override CompilationOptions CreateCompilationOptions() + { + return new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: _allowUnsafeBlocks); + } + + /// + protected override ParseOptions CreateParseOptions() + { + return new CSharpParseOptions(_languageVersion, DocumentationMode.Diagnose); + } + + /// + /// The source code to analyze. + /// Whether to enable unsafe blocks. + /// The language version to use to run the test. + public static Task VerifyAnalyzerAsync( + string source, + bool allowUnsafeBlocks = true, + LanguageVersion languageVersion = LanguageVersion.CSharp12) + { + CSharpAnalyzerWithLanguageVersionTest test = new(allowUnsafeBlocks, languageVersion) { TestCode = source }; + + test.TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net80; + test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(ComWrappersSupport).Assembly.Location)); + + return test.RunAsync(CancellationToken.None); + } +} \ No newline at end of file diff --git a/src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj b/src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj index 2a417520c..b007553e5 100644 --- a/src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj +++ b/src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj @@ -11,4 +11,9 @@ + + + + + From 32b440b3341c6534c46d2c47a2df040de37b1024 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 13:11:54 -0800 Subject: [PATCH 13/40] Fix folder for new tests --- .../SourceGeneratorTest/DiagnosticAnalyzerTests.cs | 0 .../CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs | 0 .../SourceGeneratorTest/SourceGeneratorTest.csproj | 4 ++-- src/cswinrt.sln | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/Tests/{UnitTest => }/SourceGeneratorTest/DiagnosticAnalyzerTests.cs (100%) rename src/Tests/{UnitTest => }/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs (100%) rename src/Tests/{UnitTest => }/SourceGeneratorTest/SourceGeneratorTest.csproj (78%) diff --git a/src/Tests/UnitTest/SourceGeneratorTest/DiagnosticAnalyzerTests.cs b/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs similarity index 100% rename from src/Tests/UnitTest/SourceGeneratorTest/DiagnosticAnalyzerTests.cs rename to src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs diff --git a/src/Tests/UnitTest/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs b/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs similarity index 100% rename from src/Tests/UnitTest/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs rename to src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs diff --git a/src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj b/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj similarity index 78% rename from src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj rename to src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj index b007553e5..53de8e4f9 100644 --- a/src/Tests/UnitTest/SourceGeneratorTest/SourceGeneratorTest.csproj +++ b/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj @@ -13,7 +13,7 @@ - - + + diff --git a/src/cswinrt.sln b/src/cswinrt.sln index 60f7a8a86..11da8efdf 100644 --- a/src/cswinrt.sln +++ b/src/cswinrt.sln @@ -174,7 +174,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NonWinRT", "Tests\Functiona EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OptInMode", "Tests\FunctionalTests\OptInMode\OptInMode.csproj", "{FFC0B06E-78E7-44D5-8E67-8FE5744CE071}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGeneratorTest", "Tests\UnitTest\SourceGeneratorTest\SourceGeneratorTest.csproj", "{CB7C338F-3850-4744-A1EA-3DC47B703C4A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGeneratorTest", "Tests\SourceGeneratorTest\SourceGeneratorTest.csproj", "{CB7C338F-3850-4744-A1EA-3DC47B703C4A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 694923cccb48e59d4f2bb5f7d752e7e451d02f95 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 13:13:06 -0800 Subject: [PATCH 14/40] Run new tests in CI --- .../CsWinRT-BuildAndTest-Stage.yml | 10 ++++++++++ src/build.cmd | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml b/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml index 244bcd3dd..599bf2516 100644 --- a/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml +++ b/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml @@ -62,6 +62,16 @@ stages: arguments: --diag $(Build.ArtifactStagingDirectory)\unittest\test.log --no-build --logger xunit;LogFilePath=UNITTEST-$(Build.BuildNumber).xml /nologo /m /p:platform=$(BuildPlatform);configuration=$(BuildConfiguration);CIBuildReason=CI -- RunConfiguration.TreatNoTestsAsError=true testRunTitle: Unit Tests +# Run Source Generator Tests + - task: DotNetCoreCLI@2 + displayName: Run Source Generator Tests + condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'))) + inputs: + command: test + projects: 'src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj' + arguments: --diag $(Build.ArtifactStagingDirectory)\unittest\test.log --no-build --logger trx;LogFilePath=UNITTEST-$(Build.BuildNumber).trx /nologo /m /p:platform=$(BuildPlatform);configuration=$(BuildConfiguration);CIBuildReason=CI -- RunConfiguration.TreatNoTestsAsError=true + testRunTitle: Unit Tests + # Run Embedded Unit Tests - task: DotNetCoreCLI@2 displayName: Run Embedded Unit Tests diff --git a/src/build.cmd b/src/build.cmd index 5249236e3..ef72a2d9f 100644 --- a/src/build.cmd +++ b/src/build.cmd @@ -265,6 +265,16 @@ if ErrorLevel 1 ( exit /b !ErrorLevel! ) +:sourcegeneratortest +rem Running Source Generator Unit Tests +echo Running source generator tests for %cswinrt_platform% %cswinrt_configuration% +call :exec %dotnet_exe% test --verbosity normal --no-build --logger trx;LogFilePath=%~dp0sourcegeneratortest_%cswinrt_version_string%.trx %this_dir%Tests\SourceGeneratorTest\SourceGeneratorTest.csproj /nologo /m /p:configuration=%cswinrt_configuration% -- RunConfiguration.TreatNoTestsAsError=true +if ErrorLevel 1 ( + echo. + echo ERROR: Source generator unit test failed, skipping NuGet pack + exit /b !ErrorLevel! +) + :hosttest rem Run WinRT.Host tests echo Running cswinrt host tests for %cswinrt_platform% %cswinrt_configuration% From 827a09518b5276496ac4afb3a7230ffb71cb8c36 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 18:21:06 -0800 Subject: [PATCH 15/40] Rename source generator project --- .../AnalyzerReleases.Shipped.md | 114 +- .../AnalyzerReleases.Unshipped.md | 12 +- .../AotOptimizer.cs | 3970 ++++++------ .../CollectionExpressionAnalyzer.cs | 0 .../CollectionExpressionIDE0300Suppressor.cs | 0 .../CollectionExpressionIDE0303Suppressor.cs | 0 .../CollectionExpressionIDE0305Suppressor.cs | 0 .../CollectionExpressionSuppressor.cs | 0 .../CsWinRTDiagnosticStrings.Designer.cs | 1512 ++--- .../CsWinRTDiagnosticStrings.resx | 600 +- .../DiagnosticHelpers.cs | 824 +-- .../DiagnosticUtils.cs | 0 .../Extensions/SymbolExtensions.cs | 0 .../Generator.cs | 998 +-- .../GenericVtableInitializerStrings.cs | 3476 +++++----- .../Helper.cs | 2502 +++---- .../ImmutableEquatableArray.cs | 378 +- .../Logger.cs | 0 ...eReferencedActivationFactoriesGenerator.cs | 0 .../Properties/launchSettings.json | 0 .../RcwReflectionFallbackGenerator.cs | 56 +- .../ResX/de-DE/CsWinRTDiagnosticStrings.resx | 540 +- .../ResX/es-ES/CsWinRTDiagnosticStrings.resx | 540 +- .../ResX/fr-FR/CsWinRTDiagnosticStrings.resx | 540 +- .../ResX/it-IT/CsWinRTDiagnosticStrings.resx | 540 +- .../ResX/ja-JP/CsWinRTDiagnosticStrings.resx | 540 +- .../ResX/ko-KR/CsWinRTDiagnosticStrings.resx | 540 +- .../ResX/pt-BR/CsWinRTDiagnosticStrings.resx | 540 +- .../ResX/ru-RU/CsWinRTDiagnosticStrings.resx | 540 +- .../ResX/zh-CN/CsWinRTDiagnosticStrings.resx | 540 +- .../ResX/zh-TW/CsWinRTDiagnosticStrings.resx | 540 +- .../TypeMapper.cs | 0 .../WinRT.SourceGenerator.Roslyn4080.csproj} | 0 .../WinRTAotCodeFixer.cs | 1086 ++-- .../WinRTRules.cs | 0 .../WinRTSuppressions.cs | 0 .../WinRTTypeWriter.cs | 5720 ++++++++--------- src/Authoring/cswinmd/CsWinMD.csproj | 2 +- .../Windows.UI.Xaml/Windows.UI.Xaml.csproj | 2 +- src/Projections/Windows/Windows.csproj | 2 +- .../SourceGeneratorTest.csproj | 4 +- src/cswinrt.sln | 2 +- 42 files changed, 13330 insertions(+), 13330 deletions(-) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/AnalyzerReleases.Shipped.md (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/AnalyzerReleases.Unshipped.md (97%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/AotOptimizer.cs (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/CollectionExpressions/CollectionExpressionAnalyzer.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/CollectionExpressions/CollectionExpressionSuppressor.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/CsWinRTDiagnosticStrings.Designer.cs (97%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/DiagnosticHelpers.cs (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/DiagnosticUtils.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/Extensions/SymbolExtensions.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/Generator.cs (97%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/GenericVtableInitializerStrings.cs (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/Helper.cs (97%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ImmutableEquatableArray.cs (97%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/Logger.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/MergeReferencedActivationFactoriesGenerator.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/Properties/launchSettings.json (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/RcwReflectionFallbackGenerator.cs (99%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/de-DE/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/es-ES/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/fr-FR/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/it-IT/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/ja-JP/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/ko-KR/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/pt-BR/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/ru-RU/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/zh-CN/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/ResX/zh-TW/CsWinRTDiagnosticStrings.resx (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/TypeMapper.cs (100%) rename src/Authoring/{WinRT.SourceGenerator/WinRT.SourceGenerator.csproj => WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj} (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/WinRTAotCodeFixer.cs (98%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/WinRTRules.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/WinRTSuppressions.cs (100%) rename src/Authoring/{WinRT.SourceGenerator => WinRT.SourceGenerator.Roslyn4080}/WinRTTypeWriter.cs (97%) diff --git a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Shipped.md similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Shipped.md index 657130713..d835af3e5 100644 --- a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Shipped.md @@ -1,57 +1,57 @@ -; Shipped analyzer releases -; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md - -## Release 1.1.1 - -### New Rules -Rule ID | Category | Severity | Notes ---------|----------|----------|------- -CsWinRT1000 | Usage | Error | Property should have public `get` method -CsWinRT1001 | Usage | Error | Namespaces should match the assembly namespace or be child namespaces of the assembly namespace -CsWinRT1002 | Usage | Error | Namespaces cannot differ only by case -CsWinRT1003 | Usage | Error | Component must have at least on public type -CsWinRT1004 | Usage | Error | Public types cannot be generic -CsWinRT1005 | Usage | Error | Classes exposed to CsWinRT should be sealed -CsWinRT1006 | Usage | Error | Do not expose unsupported type -CsWinRT1007 | Usage | Error | Structs should contain at least one public field -CsWinRT1008 | Usage | Error | Interfaces should not inherit interfaces that are not valid in Windows Runtime -CsWinRT1009 | Usage | Error | Class should not have multiple constructors that take the same amount of parameters -CsWinRT1010 | Usage | Error | Methods should not use parameter names that conflict with generated parameter names -CsWinRT1011 | Usage | Error | Structs should not have private fields -CsWinRT1012 | Usage | Error | Structs should not have a constant field -CsWinRT1013 | Usage | Error | Structs should only contain basic types or other structs -CsWinRT1014 | Usage | Error | Types should not overload an operator -CsWinRT1015 | Usage | Error | Do not use `DefaultOverloadAttribute` more than once for a set of overloads -CsWinRT1016 | Usage | Error | Exactly one overload should be marked as DefaultOverload -CsWinRT1017 | Usage | Error | Array types should be one dimensional, not jagged -CsWinRT1018 | Usage | Error | Array types should be one dimensional -CsWinRT1020 | Usage | Error | Do not pass parameters by `ref` -CsWinRT1021 | Usage | Error | Array parameters should not be marked `InAttribute` or `OutAttribute` -CsWinRT1022 | Usage | Error | Parameters should not be marked `InAttribute` or `OutAttribute` -CsWinRT1023 | Usage | Error | Array parameters should not be marked both `ReadOnlyArrayAttribute` and `WriteOnlyArrayAttribute` -CsWinRT1024 | Usage | Error | Array parameter marked `out` should not be declared `ReadOnlyArrayAttribute` -CsWinRT1025 | Usage | Error | Array parameter should be marked either `ReadOnlyArrayAttribute` or `WriteOnlyArrayAttribute` -CsWinRT1026 | Usage | Error | Non-array parameter should not be marked `ReadOnlyArrayAttribute` or `WriteOnlyArrayAttribute` -CsWinRT1027 | Usage | Error | Class incorrectly implements an interface - -## Release 2.1.0 - -### New Rules -Rule ID | Category | Severity | Notes ---------|----------|----------|------- -CsWinRT1028 | Usage | Warning | Class should be marked partial -CsWinRT1029 | Usage | Warning | Class implements WinRT interfaces generated using an older version of CsWinRT. - -## Release 2.1.2 - -### New Rules -Rule ID | Category | Severity | Notes ---------|----------|----------|------- -CsWinRT1030 | Usage | Warning | Project needs to be updated with `true` to allow generic interface code generation. - -## Release 2.3.0 - -### New Rules -Rule ID | Category | Severity | Notes ---------|----------|----------|------- -CsWinRT1031 | Usage | Warning | Collection expressions can only be used when statically verifiable for AOT support with WinRT. +; Shipped analyzer releases +; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + +## Release 1.1.1 + +### New Rules +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +CsWinRT1000 | Usage | Error | Property should have public `get` method +CsWinRT1001 | Usage | Error | Namespaces should match the assembly namespace or be child namespaces of the assembly namespace +CsWinRT1002 | Usage | Error | Namespaces cannot differ only by case +CsWinRT1003 | Usage | Error | Component must have at least on public type +CsWinRT1004 | Usage | Error | Public types cannot be generic +CsWinRT1005 | Usage | Error | Classes exposed to CsWinRT should be sealed +CsWinRT1006 | Usage | Error | Do not expose unsupported type +CsWinRT1007 | Usage | Error | Structs should contain at least one public field +CsWinRT1008 | Usage | Error | Interfaces should not inherit interfaces that are not valid in Windows Runtime +CsWinRT1009 | Usage | Error | Class should not have multiple constructors that take the same amount of parameters +CsWinRT1010 | Usage | Error | Methods should not use parameter names that conflict with generated parameter names +CsWinRT1011 | Usage | Error | Structs should not have private fields +CsWinRT1012 | Usage | Error | Structs should not have a constant field +CsWinRT1013 | Usage | Error | Structs should only contain basic types or other structs +CsWinRT1014 | Usage | Error | Types should not overload an operator +CsWinRT1015 | Usage | Error | Do not use `DefaultOverloadAttribute` more than once for a set of overloads +CsWinRT1016 | Usage | Error | Exactly one overload should be marked as DefaultOverload +CsWinRT1017 | Usage | Error | Array types should be one dimensional, not jagged +CsWinRT1018 | Usage | Error | Array types should be one dimensional +CsWinRT1020 | Usage | Error | Do not pass parameters by `ref` +CsWinRT1021 | Usage | Error | Array parameters should not be marked `InAttribute` or `OutAttribute` +CsWinRT1022 | Usage | Error | Parameters should not be marked `InAttribute` or `OutAttribute` +CsWinRT1023 | Usage | Error | Array parameters should not be marked both `ReadOnlyArrayAttribute` and `WriteOnlyArrayAttribute` +CsWinRT1024 | Usage | Error | Array parameter marked `out` should not be declared `ReadOnlyArrayAttribute` +CsWinRT1025 | Usage | Error | Array parameter should be marked either `ReadOnlyArrayAttribute` or `WriteOnlyArrayAttribute` +CsWinRT1026 | Usage | Error | Non-array parameter should not be marked `ReadOnlyArrayAttribute` or `WriteOnlyArrayAttribute` +CsWinRT1027 | Usage | Error | Class incorrectly implements an interface + +## Release 2.1.0 + +### New Rules +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +CsWinRT1028 | Usage | Warning | Class should be marked partial +CsWinRT1029 | Usage | Warning | Class implements WinRT interfaces generated using an older version of CsWinRT. + +## Release 2.1.2 + +### New Rules +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +CsWinRT1030 | Usage | Warning | Project needs to be updated with `true` to allow generic interface code generation. + +## Release 2.3.0 + +### New Rules +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +CsWinRT1031 | Usage | Warning | Collection expressions can only be used when statically verifiable for AOT support with WinRT. diff --git a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Unshipped.md b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Unshipped.md similarity index 97% rename from src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Unshipped.md rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Unshipped.md index f01afd2bf..6640189c3 100644 --- a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Unshipped.md +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Unshipped.md @@ -1,6 +1,6 @@ -; Unshipped analyzer release -; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md - -### New Rules -Rule ID | Category | Severity | Notes ---------|----------|----------|------- +; Unshipped analyzer release +; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + +### New Rules +Rule ID | Category | Severity | Notes +--------|----------|----------|------- diff --git a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/AotOptimizer.cs similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/AotOptimizer.cs index 49c7ca1e4..e8957e9e7 100644 --- a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/AotOptimizer.cs @@ -1,1985 +1,1985 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Operations; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Text; -using System.Threading; -using WinRT.SourceGenerator; - -namespace Generator -{ - [Generator] - public class WinRTAotSourceGenerator : IIncrementalGenerator - { - public void Initialize(IncrementalGeneratorInitializationContext context) - { - var properties = context.AnalyzerConfigOptionsProvider - .Combine(context.CompilationProvider) - .Select(static ((AnalyzerConfigOptionsProvider provider, Compilation compilation) value, CancellationToken _) => - new CsWinRTAotOptimizerProperties( - value.provider.IsCsWinRTAotOptimizerEnabled(), - value.provider.IsCsWinRTComponent(), - value.provider.IsCsWinRTCcwLookupTableGeneratorEnabled(), - GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(value.provider, value.compilation)) - ); - - var assemblyName = context.CompilationProvider.Select(static (compilation, _) => GeneratorHelper.EscapeAssemblyNameForIdentifier(compilation.AssemblyName)); - - var propertiesAndAssemblyName = properties.Combine(assemblyName); - - var typeMapperAndProperties = context.AnalyzerConfigOptionsProvider - .Select(static (options, ct) => options.GetCsWinRTUseWindowsUIXamlProjections()) - .Select(static (mode, ct) => new TypeMapper(mode)) - .Combine(properties); - - var vtablesToAddFromDetectedClassTypes = context.SyntaxProvider.CreateSyntaxProvider( - static (n, _) => NeedVtableAttribute(n), - static (n, _) => n) - .Combine(typeMapperAndProperties) - .Select(static ((GeneratorSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, CancellationToken _) => - value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerInAutoMode ? - GetVtableAttributeToAdd(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, false, value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled) : default) - .Where(static vtableAttribute => vtableAttribute != default); - - var autoDetectedVtableAttributesToAdd = vtablesToAddFromDetectedClassTypes.Select(static (vtable, _) => vtable.Item1); - var autoDetectedAdapterTypesToAddOnLookupTable = vtablesToAddFromDetectedClassTypes.SelectMany(static (vtable, _) => vtable.Item2); - - var vtablesToAddFromOptInClassTypes = context.SyntaxProvider.ForAttributeWithMetadataName( - "WinRT.GeneratedWinRTExposedTypeAttribute", - static (n, _) => NeedVtableAttribute(n), - static (n, _) => n) - .Combine(typeMapperAndProperties) - .Select(static ((GeneratorAttributeSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, CancellationToken _) => - value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerEnabled ? - GetVtableAttributeToAdd(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, false, value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled) : default) - .Where(static vtableAttribute => vtableAttribute != default); - - var optinVtableAttributesToAdd = vtablesToAddFromOptInClassTypes.Select(static (vtable, _) => vtable.Item1); - var optinAdapterTypesToAddOnLookupTable = vtablesToAddFromOptInClassTypes.SelectMany(static (vtable, _) => vtable.Item2); - - // Merge both auto detected vtables and opt-in vtables. - var vtableAttributesToAdd = autoDetectedVtableAttributesToAdd.Collect().Combine(optinVtableAttributesToAdd.Collect()).SelectMany(static (value, _) => value.Left.AddRange(value.Right).Distinct()); - context.RegisterImplementationSourceOutput(vtableAttributesToAdd.Collect().Combine(propertiesAndAssemblyName), GenerateVtableAttributes); - - // Get the vtables for component types. This is used for filtering out generic interfaces - // that will already be generated by the component generator. - var vtablesFromComponentTypes = context.SyntaxProvider.CreateSyntaxProvider( - static (n, _) => IsComponentType(n), - static (n, _) => n) - .Combine(typeMapperAndProperties) - // Get component types if only authoring scenario and if aot optimizer enabled. - .Select(static ((GeneratorSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, CancellationToken _) => - value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerEnabled && value.typeMapperAndProperties.properties.IsCsWinRTComponent ? - GetVtableAttributeToAdd(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, true, true) : default) - .Where(static vtableAttribute => vtableAttribute != default); - - var autoDetectedInstantiatedTypesToAddOnLookupTable = context.SyntaxProvider.CreateSyntaxProvider( - static (n, _) => NeedVtableOnLookupTable(n), - static (n, _) => n) - .Combine(typeMapperAndProperties) - .Select(static ((GeneratorSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, - CancellationToken _) => - value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerInAutoMode && value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled ? - GetVtableAttributesToAddOnLookupTable(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, value.typeMapperAndProperties.properties.IsCsWinRTComponent) : - (EquatableArray)ImmutableArray.Empty) - .SelectMany(static (vtable, _) => vtable) - .Where(static vtableAttribute => vtableAttribute != null); - - var optinInstantiatedTypesToAddOnLookupTable = context.SyntaxProvider.ForAttributeWithMetadataName( - "WinRT.GeneratedWinRTExposedExternalTypeAttribute", - static (n, _) => true, - static (n, _) => n) - .Combine(typeMapperAndProperties) - .Select(static ((GeneratorAttributeSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, - CancellationToken _) => - value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerEnabled && value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled ? - GetVtableAttributesToAddOnLookupTable(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, value.typeMapperAndProperties.properties.IsCsWinRTComponent) : - (EquatableArray)ImmutableArray.Empty) - .SelectMany(static (vtable, _) => vtable) - .Where(static vtableAttribute => vtableAttribute != null); - - var instantiatedTaskAdapters = context.SyntaxProvider.CreateSyntaxProvider( - static (n, _) => IsAsyncOperationMethodCall(n), - static (n, _) => n) - .Combine(typeMapperAndProperties) - .Select(static ((GeneratorSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, - CancellationToken _) => - value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerInAutoMode && value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled ? - GetVtableAttributesForTaskAdapters(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, value.typeMapperAndProperties.properties.IsCsWinRTComponent) : default) - .Where(static vtableAttribute => vtableAttribute != default) - .Collect(); - - // Merge both adapter types lists and instantiated types lists. - var vtablesToAddOnLookupTable = - autoDetectedInstantiatedTypesToAddOnLookupTable.Collect(). - Combine(autoDetectedAdapterTypesToAddOnLookupTable.Collect()). - Combine(optinInstantiatedTypesToAddOnLookupTable.Collect()). - Combine(optinAdapterTypesToAddOnLookupTable.Collect()). - Combine(instantiatedTaskAdapters). - SelectMany(static (value, _) => - value.Left.Left.Left.Left - .AddRange(value.Left.Left.Left.Right) - .AddRange(value.Left.Left.Right) - .AddRange(value.Left.Right) - .AddRange(value.Right) - .Distinct() - ); - - var genericInterfacesFromVtableAttribute = vtableAttributesToAdd.Combine(properties).SelectMany( - static ((VtableAttribute vtableAttribute, CsWinRTAotOptimizerProperties properties) value, CancellationToken _) => - // If this is a CsWinRT component, the public types are handled by the component source generator rather than - // the AOT source generator. So we filter those out here. - (!value.properties.IsCsWinRTComponent || (value.properties.IsCsWinRTComponent && !value.vtableAttribute.IsPublic)) ? - value.vtableAttribute.GenericInterfaces : (EquatableArray)ImmutableArray.Empty).Collect(); - var genericInterfacesFromVtableLookupTable = vtablesToAddOnLookupTable.SelectMany(static (vtable, _) => vtable.GenericInterfaces).Collect(); - - // The component generator generates vtable attributes for public types. The generic interfaces used by those types or its adapter types - // can overlap with the ones being generated here. So get which ones are already generated to be able to filter them out. - var genericInterfacesGeneratedByComponentGenerator = vtablesFromComponentTypes. - SelectMany(static ((VtableAttribute vtableAttribute, EquatableArray adapterTypes) classType, CancellationToken _) => - classType.vtableAttribute.GenericInterfaces.Union(classType.adapterTypes.SelectMany(static v => v.GenericInterfaces)).Distinct()). - Collect(); - - context.RegisterImplementationSourceOutput( - genericInterfacesFromVtableAttribute - .Combine(genericInterfacesFromVtableLookupTable) - .Combine(genericInterfacesGeneratedByComponentGenerator) - .Combine(propertiesAndAssemblyName), - GenerateCCWForGenericInstantiation); - - context.RegisterImplementationSourceOutput(vtablesToAddOnLookupTable.Collect().Combine(propertiesAndAssemblyName), GenerateVtableLookupTable); - - var bindableCustomPropertyAttributes = context.SyntaxProvider.ForAttributeWithMetadataName( - "WinRT.GeneratedBindableCustomPropertyAttribute", - static (n, _) => NeedCustomPropertyImplementation(n), - static (n, _) => n) - .Combine(properties) - .Select(static ((GeneratorAttributeSyntaxContext generatorSyntaxContext, CsWinRTAotOptimizerProperties properties) value, CancellationToken _) => - value.properties.IsCsWinRTAotOptimizerEnabled ? GetBindableCustomProperties(value.generatorSyntaxContext) : default) - .Where(static bindableCustomProperties => bindableCustomProperties != default) - .Collect() - .Combine(properties); - context.RegisterImplementationSourceOutput(bindableCustomPropertyAttributes, GenerateBindableCustomProperties); - } - - // Restrict to non-projected classes which can be instantiated - // and are partial allowing to add attributes. - private static bool NeedVtableAttribute(SyntaxNode node) - { - return node is ClassDeclarationSyntax declaration && - !declaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword) || m.IsKind(SyntaxKind.AbstractKeyword)) && - GeneratorHelper.IsPartial(declaration) && - !GeneratorHelper.IsWinRTType(declaration); // Making sure it isn't an RCW we are projecting. - } - - // Filters to non WinRT types which are public and can be instantiated. - // This is used to try to determine types which a component source generator will process. - private static bool IsComponentType(SyntaxNode node) - { - return node is ClassDeclarationSyntax declaration && - !declaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword) || m.IsKind(SyntaxKind.AbstractKeyword)) && - declaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.PublicKeyword)) && - !GeneratorHelper.IsWinRTType(declaration); // Making sure it isn't an RCW we are projecting. - } - - private static bool NeedCustomPropertyImplementation(SyntaxNode node) - { - if ((node is ClassDeclarationSyntax classDeclaration && !classDeclaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword) || m.IsKind(SyntaxKind.AbstractKeyword))) || - (node is RecordDeclarationSyntax recordDeclaration && !recordDeclaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword) || m.IsKind(SyntaxKind.AbstractKeyword))) || - (node is StructDeclarationSyntax structDeclaration && !structDeclaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword)))) - { - TypeDeclarationSyntax typeDeclaration = (TypeDeclarationSyntax)node; - - return GeneratorHelper.IsPartial(typeDeclaration); - } - - return false; - } - - private static (VtableAttribute, EquatableArray) GetVtableAttributeToAdd( - GeneratorSyntaxContext context, - TypeMapper typeMapper, - bool checkForComponentTypes, - bool isCsWinRTCcwLookupTableGeneratorEnabled) - { - return GetVtableAttributeToAdd( - context.SemanticModel.GetDeclaredSymbol(context.Node as ClassDeclarationSyntax), - typeMapper, - context.SemanticModel.Compilation, - checkForComponentTypes, - isCsWinRTCcwLookupTableGeneratorEnabled); - } - - private static (VtableAttribute, EquatableArray) GetVtableAttributeToAdd( - GeneratorAttributeSyntaxContext context, - TypeMapper typeMapper, - bool checkForComponentTypes, - bool isCsWinRTCcwLookupTableGeneratorEnabled) - { - return GetVtableAttributeToAdd( - (ITypeSymbol)context.TargetSymbol, - typeMapper, - context.SemanticModel.Compilation, - checkForComponentTypes, - isCsWinRTCcwLookupTableGeneratorEnabled); - } - - private static (VtableAttribute, EquatableArray) GetVtableAttributeToAdd( - ITypeSymbol symbol, - TypeMapper typeMapper, - Compilation compilation, - bool checkForComponentTypes, - bool isCsWinRTCcwLookupTableGeneratorEnabled) - { - var isManagedOnlyType = GeneratorHelper.IsManagedOnlyType(compilation); - var isWinRTTypeFunc = GeneratorHelper.IsWinRTType(compilation, checkForComponentTypes); - var vtableAttribute = GetVtableAttributeToAdd(symbol, isManagedOnlyType, isWinRTTypeFunc, typeMapper, compilation, false); - if (vtableAttribute != default) - { - HashSet vtableAttributesForLookupTable = []; - // Add any adapter types which may be needed if certain functions - // from some known interfaces are called. - if (isCsWinRTCcwLookupTableGeneratorEnabled) - { - AddVtableAdapterTypeForKnownInterface(symbol, compilation, isManagedOnlyType, isWinRTTypeFunc, typeMapper, vtableAttributesForLookupTable); - } - return (vtableAttribute, vtableAttributesForLookupTable.ToImmutableArray()); - } - - return default; - } - - // There are several async operation related methods that can be called. - // But they are all under the AsyncInfo static class or is the AsAsyncOperation - // extension method. - static bool IsAsyncOperationMethodCall(SyntaxNode node) - { - if (node is InvocationExpressionSyntax methodInvoke && - methodInvoke.Expression is MemberAccessExpressionSyntax methodAccess) - { - // Check for static class as a way of handling all the async functions from it. - if (methodAccess.Expression is IdentifierNameSyntax className && - className.Identifier.ValueText == "AsyncInfo") - { - return true; - } - - // Check for calling the fully qualified static class. - // i.e. System.Runtime.InteropServices.WindowsRuntime.AsyncInfo - if (methodAccess.Expression is MemberAccessExpressionSyntax memberAccess && - memberAccess.Name.Identifier.ValueText == "AsyncInfo") - { - return true; - } - - // Check for function call for the scenario that doesn't use the static class. - if (methodAccess.Name is IdentifierNameSyntax methodName) - { - return methodName.Identifier.ValueText == "AsAsyncOperation"; - } - } - - return false; - } - - // Detect if AsAsyncOperation or similar function is being called and if so, - // make sure the generic adapter type we use for it is on the lookup table. - // We do this both assuming this is not an authoring component and is an authoring - // component as we don't know that at this stage and the results can vary based on that. - // We will choose the right one later when we can combine with properties. - private static VtableAttribute GetVtableAttributesForTaskAdapters(GeneratorSyntaxContext context, TypeMapper typeMapper, bool isCsWinRTComponent) - { - // Generic instantiation of task adapters make of use of unsafe. - // This will be caught by GetVtableAttributeToAdd, but catching it early here too. - if (!GeneratorHelper.AllowUnsafe(context.SemanticModel.Compilation)) - { - return default; - } - - if (context.SemanticModel.GetSymbolInfo(context.Node as InvocationExpressionSyntax).Symbol is IMethodSymbol symbol) - { - var adapterTypeStr = GeneratorHelper.GetTaskAdapterIfAsyncMethod(symbol); - if (!string.IsNullOrEmpty(adapterTypeStr)) - { - var adpaterType = context.SemanticModel.Compilation.GetTypeByMetadataName(adapterTypeStr); - if (adpaterType is not null) - { - var constructedAdapterType = adpaterType.Construct([.. symbol.TypeArguments]); - return GetVtableAttributeToAdd( - constructedAdapterType, - GeneratorHelper.IsManagedOnlyType(context.SemanticModel.Compilation), - GeneratorHelper.IsWinRTType(context.SemanticModel.Compilation, isCsWinRTComponent), - typeMapper, - context.SemanticModel.Compilation, - false); - } - } - } - - return default; - } - -#nullable enable - private static BindableCustomProperties GetBindableCustomProperties(GeneratorAttributeSyntaxContext context) - { - // We expect a class with a single attribute. - var symbol = (INamedTypeSymbol)context.TargetSymbol; - var attributeData = context.Attributes.First(); - - List bindableCustomProperties = new(); - - // Make all public properties in the class bindable including ones in base type. - if (attributeData.ConstructorArguments.Length == 0) - { - for (var curSymbol = symbol; curSymbol != null; curSymbol = curSymbol.BaseType) - { - foreach (var propertySymbol in curSymbol.GetMembers(). - Where(static m => m.Kind == SymbolKind.Property && - m.DeclaredAccessibility == Accessibility.Public)) - { - AddProperty(propertySymbol); - } - } - } - // Make specified public properties in the class bindable including ones in base type. - else if (attributeData.ConstructorArguments is - [ - { Kind: TypedConstantKind.Array, Values: [..] propertyNames }, - { Kind: TypedConstantKind.Array, Values: [..] propertyIndexerTypes } - ]) - { - for (var curSymbol = symbol; curSymbol != null; curSymbol = curSymbol.BaseType) - { - foreach (var member in curSymbol.GetMembers()) - { - if (member is IPropertySymbol propertySymbol && - member.DeclaredAccessibility == Accessibility.Public) - { - if (!propertySymbol.IsIndexer && - propertyNames.Any(p => p.Value is string value && value == propertySymbol.Name)) - { - AddProperty(propertySymbol); - } - else if (propertySymbol.IsIndexer && - // ICustomProperty only supports single indexer parameter. - propertySymbol.Parameters.Length == 1 && - propertyIndexerTypes.Any(p => p.Value is ISymbol typeSymbol && typeSymbol.Equals(propertySymbol.Parameters[0].Type, SymbolEqualityComparer.Default))) - { - AddProperty(propertySymbol); - } - } - } - } - } - - var typeName = ToFullyQualifiedString(symbol); - bool isGlobalNamespace = symbol.ContainingNamespace == null || symbol.ContainingNamespace.IsGlobalNamespace; - var @namespace = symbol.ContainingNamespace?.ToDisplayString(); - if (!isGlobalNamespace) - { - typeName = typeName[(@namespace!.Length + 1)..]; - } - - EquatableArray classHierarchy = ImmutableArray.Empty; - - // Gather the type hierarchy, only if the type is nested (as an optimization) - if (symbol.ContainingType is not null) - { - List hierarchyList = new(); - - for (ITypeSymbol parent = symbol; parent is not null; parent = parent.ContainingType) - { - hierarchyList.Add(new TypeInfo( - parent.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), - parent.TypeKind, - parent.IsRecord)); - } - - classHierarchy = ImmutableArray.CreateRange(hierarchyList); - } - - return new BindableCustomProperties( - @namespace, - isGlobalNamespace, - typeName, - symbol.TypeKind, - symbol.IsRecord, - classHierarchy, - ToFullyQualifiedString(symbol), - bindableCustomProperties.ToImmutableArray()); - - void AddProperty(ISymbol symbol) - { - if (symbol is IPropertySymbol propertySymbol) - { - bindableCustomProperties.Add(new BindableCustomProperty( - propertySymbol.MetadataName, - ToFullyQualifiedString(propertySymbol.Type), - // Make sure the property accessors are also public even if property itself is public. - propertySymbol.GetMethod != null && propertySymbol.GetMethod.DeclaredAccessibility == Accessibility.Public, - propertySymbol.SetMethod != null && !propertySymbol.SetMethod.IsInitOnly && propertySymbol.SetMethod.DeclaredAccessibility == Accessibility.Public, - propertySymbol.IsIndexer, - propertySymbol.IsIndexer ? ToFullyQualifiedString(propertySymbol.Parameters[0].Type) : "", - propertySymbol.IsStatic - )); - } - } - } -#nullable disable - - private static string ToFullyQualifiedString(ISymbol symbol) - { - // Used to ensure class names within generics are fully qualified to avoid - // having issues when put in ABI namespaces. - var symbolDisplayString = new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes | SymbolDisplayMiscellaneousOptions.ExpandNullable); - - var qualifiedString = symbol.ToDisplayString(symbolDisplayString); - return qualifiedString.StartsWith("global::") ? qualifiedString[8..] : qualifiedString; - } - - private static string ToVtableLookupString(ISymbol symbol) - { - List genericArguments = []; - var fullName = ToVtableLookupString(symbol, genericArguments); - if (genericArguments.Count == 0) - { - return fullName; - } - - return $$"""{{fullName}}[{{string.Join(",", genericArguments)}}]"""; - } - - private static string ToVtableLookupString(ISymbol symbol, List genericArguments, bool ignoreTypeArguments = false) - { - if (symbol is INamedTypeSymbol namedTypeSymbol && - !ignoreTypeArguments && - namedTypeSymbol.TypeArguments.Length != 0) - { - // Ignore type arguments and get the string representation for the rest of - // the type to properly handle nested types. - var fullName = ToVtableLookupString(symbol, genericArguments, true); - // Type arguments are collected but not added to the type name until the end - // per the format of Type.ToString(). ToVtableLookupString on the symbol is - // also called first to ensure any type arguments from any nested parent types - // are added first. - foreach (var typeArgument in namedTypeSymbol.TypeArguments) - { - genericArguments.Add(ToVtableLookupString(typeArgument)); - } - return fullName; - } - else - { - // If it is a generic type argument or the type is directly under a namspace, we just use the ToDisplayString API. - if (symbol is not INamedTypeSymbol || symbol.ContainingSymbol is INamespaceSymbol || symbol.ContainingSymbol is null) - { - var arity = symbol is INamedTypeSymbol namedType && namedType.Arity > 0 ? "`" + namedType.Arity : ""; - var symbolDisplayString = new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, - miscellaneousOptions: SymbolDisplayMiscellaneousOptions.ExpandNullable); - return symbol.ToDisplayString(symbolDisplayString) + arity; - } - else - { - // Nested types use + in the fully qualified name rather than . - return ToVtableLookupString(symbol.ContainingSymbol, genericArguments) + "+" + symbol.MetadataName; - } - } - } - - private static string GetRuntimeClassName( - INamedTypeSymbol type, - Func isWinRTType, - TypeMapper mapper) - { - if (type == null) - { - return string.Empty; - } - - string metadataName = string.Join(".", type.ContainingNamespace?.ToDisplayString(), type.MetadataName); - if (type.IsGenericType && !type.IsDefinition) - { - StringBuilder builder = new(); - - builder.Append(GetRuntimeClassName(type.OriginalDefinition, isWinRTType, mapper)); - builder.Append("<"); - - bool first = true; - foreach (var genericArg in type.TypeArguments) - { - if (!first) - { - builder.Append(", "); - } - - builder.Append(GetRuntimeClassName(genericArg as INamedTypeSymbol, isWinRTType, mapper)); - first = false; - } - - builder.Append(">"); - - return builder.ToString(); - } - else if (type.SpecialType == SpecialType.System_Object) - { - return "Object"; - } - else if (type.SpecialType == SpecialType.System_Byte) - { - return "UInt8"; - } - else if (type.SpecialType == SpecialType.System_SByte) - { - return "Int8"; - } - else if (mapper.HasMappingForType(metadataName)) - { - var mapping = mapper.GetMappedType(metadataName).GetMapping(); - return mapping.Item1 + "." + mapping.Item2; - } - else if (type.SpecialType != SpecialType.None) - { - return type.Name; - } - else if (isWinRTType(type, mapper)) - { - return metadataName; - } - else - { - // If we end up here, this is most likely an authoring scenario where the type is being authored - // for WinRT projection in this component. - return metadataName; - } - } - - internal static VtableAttribute GetVtableAttributeToAdd( - ITypeSymbol symbol, - Func isManagedOnlyType, - Func isWinRTType, - TypeMapper mapper, - Compilation compilation, - bool isAuthoring, - string authoringDefaultInterface = "") - { - if (symbol is null) - { - return default; - } - - if (GeneratorHelper.HasNonInstantiatedWinRTGeneric(symbol, mapper)) - { - return default; - } - - // Skip all types explicitly blocked for marshalling. - // We don't want them to affect the codegen at all. - if (isManagedOnlyType(symbol)) - { - return default; - } - - HashSet interfacesToAddToVtable = new(); - HashSet genericInterfacesToAddToVtable = new(); - - if (!string.IsNullOrEmpty(authoringDefaultInterface)) - { - interfacesToAddToVtable.Add(authoringDefaultInterface); - } - - // If the attribute is already placed on the type, don't generate a new one as we will - // use the specified one. Also for authoring scenarios where we call this for authored WinRT types, - // don't generate the runtimeclass name for them as we will rely on the full name for them as we do today. - var checkForRuntimeClasName = !GeneratorHelper.HasWinRTRuntimeClassNameAttribute(symbol, compilation) && - (!isAuthoring || (isAuthoring && !isWinRTType(symbol, mapper))); - INamedTypeSymbol interfaceToUseForRuntimeClassName = null; - foreach (var iface in symbol.AllInterfaces) - { - if (isWinRTType(iface, mapper)) - { - // If the interface projection was generated using an older CsWinRT version, - // it won't have the necessary properties to generate the AOT compatible code - // and we don't want to result in compiler errors. - // We exclude generic types as they are either defined in WinRT.Runtime or the - // Windows SDK projection, so we don't need to check them. - if (!iface.IsGenericType && - GeneratorHelper.IsOldProjectionAssembly(iface.ContainingAssembly)) - { - return default; - } - - interfacesToAddToVtable.Add(ToFullyQualifiedString(iface)); - AddGenericInterfaceInstantiation(iface); - CheckForInterfaceToUseForRuntimeClassName(iface); - } - - if (iface.IsGenericType && TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, mapper, null, isWinRTType, out var compatibleIfaces)) - { - foreach (var compatibleIface in compatibleIfaces) - { - // For covariant interfaces which are exclusive interfaces that the projection implemented - // such as overrides / protected interfaces in composable types, we don't include them in - // the vtable as they are today marked internal and we can't reference them due to that. - // If this scenarios matters where native callers do indeed QI for these exclusive - // covariant interfaces, we can in the future project them as public, but for now - // leaving as is. - if (GeneratorHelper.IsInternalInterfaceFromReferences(compatibleIface, compilation.Assembly)) - { - continue; - } - - interfacesToAddToVtable.Add(ToFullyQualifiedString(compatibleIface)); - AddGenericInterfaceInstantiation(compatibleIface); - CheckForInterfaceToUseForRuntimeClassName(compatibleIface); - } - } - } - - // KeyValueType is a value type in C#, but it is projected as a reference type in WinRT. - if (symbol.TypeKind == TypeKind.Struct && symbol.MetadataName == "KeyValuePair`2" && isWinRTType(symbol, mapper)) - { - interfacesToAddToVtable.Add(ToFullyQualifiedString(symbol)); - AddGenericInterfaceInstantiation(symbol as INamedTypeSymbol); - - // KeyValuePair is projected as an interface. - CheckForInterfaceToUseForRuntimeClassName(symbol as INamedTypeSymbol); - } - - bool isDelegate = false; - if (symbol.TypeKind == TypeKind.Delegate) - { - isDelegate = true; - interfacesToAddToVtable.Add(ToFullyQualifiedString(symbol)); - AddGenericInterfaceInstantiation(symbol as INamedTypeSymbol); - } - - if (!interfacesToAddToVtable.Any()) - { - return default; - } - - // If there are generic interfaces, the generic interface instantiations make use of - // unsafe. But if it isn't enabled, we don't want to fail to compile in case it is - // not a WinRT scenario. So we instead, don't generate the code that needs the unsafe - // and there would be a diagnostic produced by the analyzer. - if (genericInterfacesToAddToVtable.Any() && !GeneratorHelper.AllowUnsafe(compilation)) - { - return default; - } - - var typeName = ToFullyQualifiedString(symbol); - bool isGlobalNamespace = symbol.ContainingNamespace == null || symbol.ContainingNamespace.IsGlobalNamespace; - var @namespace = symbol.ContainingNamespace?.ToDisplayString(); - if (!isGlobalNamespace) - { - typeName = typeName[(@namespace.Length + 1)..]; - } - - EquatableArray classHierarchy = ImmutableArray.Empty; - - // Gather the type hierarchy, only if the type is nested (as an optimization) - if (symbol.ContainingType is not null) - { - List hierarchyList = new(); - - for (ITypeSymbol parent = symbol; parent is not null; parent = parent.ContainingType) - { - hierarchyList.Add(new TypeInfo( - parent.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), - parent.TypeKind, - parent.IsRecord)); - } - - classHierarchy = ImmutableArray.CreateRange(hierarchyList); - } - - return new VtableAttribute( - isAuthoring ? "ABI.Impl." + @namespace : @namespace, - isGlobalNamespace, - typeName, - classHierarchy, - ToVtableLookupString(symbol), - interfacesToAddToVtable.ToImmutableArray(), - genericInterfacesToAddToVtable.ToImmutableArray(), - symbol is IArrayTypeSymbol, - isDelegate, - symbol.DeclaredAccessibility == Accessibility.Public, - GetRuntimeClassName(interfaceToUseForRuntimeClassName, isWinRTType, mapper)); - - void AddGenericInterfaceInstantiation(INamedTypeSymbol iface) - { - if (iface.IsGenericType) - { - List genericParameters = new(); - foreach (var genericParameter in iface.TypeArguments) - { - var isNullable = genericParameter.IsValueType && genericParameter.NullableAnnotation.HasFlag(NullableAnnotation.Annotated); - - // Handle initialization of nested generics as they may not be - // initialized already. - if (!isNullable && - genericParameter is INamedTypeSymbol genericParameterIface && - genericParameterIface.IsGenericType) - { - AddGenericInterfaceInstantiation(genericParameterIface); - } - - genericParameters.Add(new GenericParameter( - ToFullyQualifiedString(genericParameter), - GeneratorHelper.GetAbiType(genericParameter, mapper), - isNullable ? TypeKind.Interface : genericParameter.TypeKind)); - } - - genericInterfacesToAddToVtable.Add(new GenericInterface( - ToFullyQualifiedString(iface), - $$"""{{iface.ContainingNamespace}}.{{iface.MetadataName}}""", - genericParameters.ToImmutableArray())); - } - } - - bool IsExternalInternalInterface(INamedTypeSymbol iface) - { - return (iface.DeclaredAccessibility == Accessibility.Internal && !SymbolEqualityComparer.Default.Equals(iface.ContainingAssembly, compilation.Assembly)) || - (iface.IsGenericType && iface.TypeArguments.Any(typeArgument => IsExternalInternalInterface(typeArgument as INamedTypeSymbol))); - } - - // Determines the interface to use to represent the type when GetRuntimeClassName is called. - // Given these are non WinRT types implementing WinRT interfaces, we find the most derived - // interface to represent it so that it applies for most scenarios. - void CheckForInterfaceToUseForRuntimeClassName(INamedTypeSymbol iface) - { - if (!checkForRuntimeClasName) - { - return; - } - - if (interfaceToUseForRuntimeClassName is null || compilation.HasImplicitConversion(iface, interfaceToUseForRuntimeClassName)) - { - interfaceToUseForRuntimeClassName = iface; - } - } - } - - private static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(INamedTypeSymbol type, TypeMapper mapper, Stack typeStack, Func isWinRTType, out IList compatibleTypes) - { - compatibleTypes = null; - - // Out of all the C# interfaces which are valid WinRT interfaces and - // support covariance, they all only have one generic parameter, - // so scoping to only handle that. - if (type is not { IsGenericType: true, TypeParameters: [{ Variance: VarianceKind.Out, IsValueType: false }] }) - { - return false; - } - - var definition = type.OriginalDefinition; - if (!isWinRTType(definition, mapper)) - { - return false; - } - - if (typeStack == null) - { - typeStack = new Stack(); - } - else - { - if (typeStack.Contains(type)) - { - return false; - } - } - typeStack.Push(type); - - HashSet compatibleTypesForGeneric = new(SymbolEqualityComparer.Default); - - if (isWinRTType(type.TypeArguments[0], mapper)) - { - compatibleTypesForGeneric.Add(type.TypeArguments[0]); - } - - foreach (var iface in type.TypeArguments[0].AllInterfaces) - { - if (isWinRTType(iface, mapper)) - { - compatibleTypesForGeneric.Add(iface); - } - - if (iface.IsGenericType - && TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, mapper, typeStack, isWinRTType, out var compatibleIfaces)) - { - compatibleTypesForGeneric.UnionWith(compatibleIfaces); - } - } - - var baseType = type.TypeArguments[0].BaseType; - while (baseType != null) - { - if (isWinRTType(baseType, mapper)) - { - compatibleTypesForGeneric.Add(baseType); - } - baseType = baseType.BaseType; - } - - typeStack.Pop(); - - compatibleTypes = new List(compatibleTypesForGeneric.Count); - foreach (var compatibleType in compatibleTypesForGeneric) - { - compatibleTypes.Add(definition.Construct(compatibleType)); - } - - return true; - } - - private static void GenerateVtableAttributes( - SourceProductionContext sourceProductionContext, - (ImmutableArray vtableAttributes, (CsWinRTAotOptimizerProperties properties, string escapedAssemblyName) context) value) - { - if (!value.context.properties.IsCsWinRTAotOptimizerEnabled) - { - return; - } - - GenerateVtableAttributes(sourceProductionContext.AddSource, value.vtableAttributes, value.context.properties.IsCsWinRTComponent, value.context.escapedAssemblyName); - } - - internal static string GenerateVtableEntry(VtableEntry vtableEntry, string escapedAssemblyName) - { - StringBuilder source = new(); - - foreach (var genericInterface in vtableEntry.GenericInterfaces) - { - source.AppendLine(GenericVtableInitializerStrings.GetInstantiationInitFunction( - genericInterface.GenericDefinition, - genericInterface.GenericParameters, - escapedAssemblyName)); - } - - if (vtableEntry.IsDelegate) - { - var @interface = vtableEntry.Interfaces.First(); - source.AppendLine(); - source.AppendLine($$""" - var delegateInterface = new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry - { - IID = global::ABI.{{@interface}}.IID, - Vtable = global::ABI.{{@interface}}.AbiToProjectionVftablePtr - }; - - return global::WinRT.DelegateTypeDetails<{{@interface}}>.GetExposedInterfaces(delegateInterface); - """); - } - else if (vtableEntry.Interfaces.Any()) - { - source.AppendLine(); - source.AppendLine($$""" - return new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry[] - { - """); - - foreach (var @interface in vtableEntry.Interfaces) - { - var genericStartIdx = @interface.IndexOf('<'); - var interfaceStaticsMethod = @interface[..(genericStartIdx == -1 ? @interface.Length : genericStartIdx)] + "Methods"; - if (genericStartIdx != -1) - { - interfaceStaticsMethod += @interface[genericStartIdx..@interface.Length]; - } - - source.AppendLine($$""" - new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry - { - IID = global::ABI.{{interfaceStaticsMethod}}.IID, - Vtable = global::ABI.{{interfaceStaticsMethod}}.AbiToProjectionVftablePtr - }, - """); - } - source.AppendLine($$""" - }; - """); - } - else - { - source.AppendLine($$""" - return global::System.Array.Empty(); - """); - } - - return source.ToString(); - } - - internal static void GenerateVtableAttributes(Action addSource, ImmutableArray vtableAttributes, bool isCsWinRTComponentFromAotOptimizer, string escapedAssemblyName) - { - var vtableEntryToVtableClassName = new Dictionary(); - StringBuilder vtableClassesSource = new(); - bool firstVtableClass = true; - - // Using ToImmutableHashSet to avoid duplicate entries from the use of partial classes by the developer - // to split out their implementation. When they do that, we will get multiple entries here for that - // and try to generate the same attribute and file with the same data as we use the semantic model - // to get all the symbol data rather than the data at an instance of a partial class definition. - foreach (var vtableAttribute in vtableAttributes.ToImmutableHashSet()) - { - // If this is a WinRT component project and this call is coming - // from the AOT optimizer, then any public types are not handled - // right now as they are handled by the WinRT component source generator - // calling this. - if (((isCsWinRTComponentFromAotOptimizer && !vtableAttribute.IsPublic) || !isCsWinRTComponentFromAotOptimizer) && - vtableAttribute.Interfaces.Any()) - { - StringBuilder source = new(); - if (!vtableAttribute.IsGlobalNamespace) - { - source.AppendLine($$""" - namespace {{vtableAttribute.Namespace}} - { - """); - } - - // Check if this class shares the same vtable as another class. If so, reuse the same generated class for it. - VtableEntry entry = new(vtableAttribute.Interfaces, vtableAttribute.GenericInterfaces, vtableAttribute.IsDelegate); - bool vtableEntryExists = vtableEntryToVtableClassName.TryGetValue(entry, out var ccwClassName); - if (!vtableEntryExists) - { - var @namespace = vtableAttribute.IsGlobalNamespace ? "" : $"{vtableAttribute.Namespace}."; - ccwClassName = GeneratorHelper.EscapeTypeNameForIdentifier(@namespace + vtableAttribute.ClassName); - vtableEntryToVtableClassName.Add(entry, ccwClassName); - } - - var escapedClassName = GeneratorHelper.EscapeTypeNameForIdentifier(vtableAttribute.ClassName); - - // Simple case when the type is not nested - if (vtableAttribute.ClassHierarchy.IsEmpty) - { - if (!string.IsNullOrEmpty(vtableAttribute.RuntimeClassName)) - { - source.AppendLine($$"""[global::WinRT.WinRTRuntimeClassName("{{vtableAttribute.RuntimeClassName}}")]"""); - } - - source.AppendLine($$""" - [global::WinRT.WinRTExposedType(typeof(global::WinRT.{{escapedAssemblyName}}VtableClasses.{{ccwClassName}}WinRTTypeDetails))] - partial class {{vtableAttribute.ClassName}} - { - } - """); - } - else - { - ReadOnlySpan classHierarchy = vtableAttribute.ClassHierarchy.AsSpan(); - - // If the type is nested, correctly nest the type definition - for (int i = classHierarchy.Length - 1; i > 0; i--) - { - source.AppendLine($$""" - partial {{classHierarchy[i].GetTypeKeyword()}} {{classHierarchy[i].QualifiedName}} - { - """); - } - - // Define the inner-most item with the attribute - if (!string.IsNullOrEmpty(vtableAttribute.RuntimeClassName)) - { - source.AppendLine($$"""[global::WinRT.WinRTRuntimeClassName("{{vtableAttribute.RuntimeClassName}}")]"""); - } - - source.AppendLine($$""" - [global::WinRT.WinRTExposedType(typeof(global::WinRT.{{escapedAssemblyName}}VtableClasses.{{ccwClassName}}WinRTTypeDetails))] - partial {{classHierarchy[0].GetTypeKeyword()}} {{classHierarchy[0].QualifiedName}} - { - } - """); - - // Close all brackets - for (int i = classHierarchy.Length - 1; i > 0; i--) - { - source.AppendLine("}"); - } - } - - // Only generate class, if this is the first time we run into this set of vtables. - if (!vtableEntryExists) - { - if (firstVtableClass) - { - vtableClassesSource.AppendLine($$""" - namespace WinRT.{{escapedAssemblyName}}VtableClasses - { - """); - firstVtableClass = false; - } - else - { - vtableClassesSource.AppendLine(); - } - - vtableClassesSource.AppendLine($$""" - internal sealed class {{ccwClassName}}WinRTTypeDetails : global::WinRT.IWinRTExposedTypeDetails - { - public global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry[] GetExposedInterfaces() - { - """); - - if (vtableAttribute.Interfaces.Any()) - { - foreach (var genericInterface in vtableAttribute.GenericInterfaces) - { - vtableClassesSource.AppendLine(GenericVtableInitializerStrings.GetInstantiationInitFunction( - genericInterface.GenericDefinition, - genericInterface.GenericParameters, - escapedAssemblyName)); - } - - vtableClassesSource.AppendLine(); - vtableClassesSource.AppendLine($$""" - return new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry[] - { - """); - - foreach (var @interface in vtableAttribute.Interfaces) - { - var genericStartIdx = @interface.IndexOf('<'); - var interfaceStaticsMethod = @interface[..(genericStartIdx == -1 ? @interface.Length : genericStartIdx)] + "Methods"; - if (genericStartIdx != -1) - { - interfaceStaticsMethod += @interface[genericStartIdx..@interface.Length]; - } - - vtableClassesSource.AppendLine($$""" - new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry - { - IID = global::ABI.{{interfaceStaticsMethod}}.IID, - Vtable = global::ABI.{{interfaceStaticsMethod}}.AbiToProjectionVftablePtr - }, - """); - } - vtableClassesSource.AppendLine($$""" - }; - """); - } - else - { - vtableClassesSource.AppendLine($$""" - return global::System.Array.Empty(); - """); - } - - vtableClassesSource.AppendLine($$""" - } - } - """); - } - - if (!vtableAttribute.IsGlobalNamespace) - { - source.AppendLine($@"}}"); - } - - string prefix = vtableAttribute.IsGlobalNamespace ? "" : $"{vtableAttribute.Namespace}."; - addSource($"{prefix}{escapedClassName}.WinRTVtable.g.cs", source.ToString()); - } - } - - if (vtableClassesSource.Length != 0) - { - vtableClassesSource.AppendLine("}"); - addSource($"WinRTCCWVtable.g.cs", vtableClassesSource.ToString()); - } - } - - private static void GenerateCCWForGenericInstantiation( - SourceProductionContext sourceProductionContext, - (((ImmutableArray vtableAttributeList, ImmutableArray lookupTableList) interfacesToGenerate, - ImmutableArray componentGeneratorList) genericInterfaces, - (CsWinRTAotOptimizerProperties properties, string escapedAssemblyName) context) value) - { - if (!value.context.properties.IsCsWinRTAotOptimizerEnabled) - { - return; - } - - HashSet genericInterfacesHashSet = new(value.genericInterfaces.interfacesToGenerate.vtableAttributeList); - if (value.context.properties.IsCsWinRTCcwLookupTableGeneratorEnabled) - { - genericInterfacesHashSet.UnionWith(value.genericInterfaces.interfacesToGenerate.lookupTableList); - } - - // Remove all the generic interfaces that are beign generated by the component generator. - foreach (var i in value.genericInterfaces.componentGeneratorList) - { - genericInterfacesHashSet.Remove(i); - } - - GenerateCCWForGenericInstantiation(sourceProductionContext.AddSource, genericInterfacesHashSet.ToImmutableArray(), value.context.escapedAssemblyName); - } - - internal static void GenerateCCWForGenericInstantiation(Action addSource, ImmutableArray genericInterfaces, string escapedAssemblyName) - { - StringBuilder source = new(); - - if (genericInterfaces.Any()) - { - source.AppendLine($$""" - using System; - using System.Runtime.InteropServices; - using System.Runtime.CompilerServices; - - namespace WinRT.{{escapedAssemblyName}}GenericHelpers - { - """); - } - - var updatedGenericInterfaces = GenericVtableInitializerStrings.AddDependentGenericInterfaces(genericInterfaces.ToImmutableHashSet()); - foreach (var genericInterface in updatedGenericInterfaces) - { - source.AppendLine(); - source.AppendLine("// " + genericInterface.Interface); - source.AppendLine(GenericVtableInitializerStrings.GetInstantiation( - genericInterface.GenericDefinition, - genericInterface.GenericParameters)); - } - - if (genericInterfaces.Any()) - { - source.AppendLine("}"); - addSource($"WinRTGenericInstantiation.g.cs", source.ToString()); - } - } - - private static bool NeedVtableOnLookupTable(SyntaxNode node) - { - return (node is InvocationExpressionSyntax invocation && invocation.ArgumentList.Arguments.Count != 0) || - node is AssignmentExpressionSyntax || - node is VariableDeclarationSyntax || - node is PropertyDeclarationSyntax || - node is ReturnStatementSyntax || - node is CollectionExpressionSyntax; - } - - private static EquatableArray GetVtableAttributesToAddOnLookupTable( - GeneratorSyntaxContext context, - TypeMapper typeMapper, - bool isCsWinRTComponent) - { - var isWinRTType = GeneratorHelper.IsWinRTType(context.SemanticModel.Compilation, isCsWinRTComponent); - return GetVtableAttributesToAddOnLookupTable( - context, - typeMapper, - GeneratorHelper.IsManagedOnlyType(context.SemanticModel.Compilation), - isWinRTType, - GeneratorHelper.IsWinRTClassOrInterface(context.SemanticModel.Compilation, isWinRTType, typeMapper)); - } - - private static EquatableArray GetVtableAttributesToAddOnLookupTable( - GeneratorSyntaxContext context, - TypeMapper typeMapper, - Func isManagedOnlyType, - Func isWinRTType, - Func isWinRTClassOrInterface) - { - HashSet visitedTypes = new(SymbolEqualityComparer.Default); - HashSet vtableAttributes = new(); - - if (context.Node is InvocationExpressionSyntax invocation) - { - var invocationSymbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol; - if (invocationSymbol is IMethodSymbol methodSymbol && - // Filter checks for boxing and casts to ones calling CsWinRT projected functions and - // functions within same assembly. Functions within same assembly can take a boxed value - // and end up calling a projection function (i.e. ones generated by XAML compiler) - // In theory, another library can also be called which can call a projected function - // but not handling those scenarios for now. - (isWinRTClassOrInterface(methodSymbol.ContainingSymbol, true) || - SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) - { - // Get the concrete types directly from the argument rather than - // using what the method accepts, which might just be an interface, so - // that we can try to include any other WinRT interfaces implemented by - // that type on the CCW when it is marshaled. - for (int idx = 0, paramsIdx = 0; idx < invocation.ArgumentList.Arguments.Count; idx++) - { - if (methodSymbol.Parameters[paramsIdx].RefKind != RefKind.Out) - { - var argumentType = context.SemanticModel.GetTypeInfo(invocation.ArgumentList.Arguments[idx].Expression); - AddVtableAttributesForType(argumentType, methodSymbol.Parameters[paramsIdx].Type); - } - - // The method parameter can be declared as params which means - // an array of arguments can be passed for it and it is the - // last argument. - if (!methodSymbol.Parameters[paramsIdx].IsParams) - { - paramsIdx++; - } - } - } - } - else if (context.Node is AssignmentExpressionSyntax assignment) - { - var leftSymbol = context.SemanticModel.GetSymbolInfo(assignment.Left).Symbol; - if (leftSymbol is IPropertySymbol propertySymbol && - (isWinRTClassOrInterface(propertySymbol.ContainingSymbol, true) || - SymbolEqualityComparer.Default.Equals(propertySymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) - { - AddVtableAttributesForType(context.SemanticModel.GetTypeInfo(assignment.Right), propertySymbol.Type); - } - else if (leftSymbol is IFieldSymbol fieldSymbol && - // WinRT interfaces don't have fields, so we don't need to check for them. - (isWinRTClassOrInterface(fieldSymbol.ContainingSymbol, false) || - SymbolEqualityComparer.Default.Equals(fieldSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) - { - AddVtableAttributesForType(context.SemanticModel.GetTypeInfo(assignment.Right), fieldSymbol.Type); - } - } - else if (context.Node is VariableDeclarationSyntax variableDeclaration) - { - // Detect scenarios where the variable declaration is to a boxed or cast type during initialization. - var leftSymbol = context.SemanticModel.GetSymbolInfo(variableDeclaration.Type).Symbol; - if (leftSymbol is INamedTypeSymbol namedType) - { - foreach (var variable in variableDeclaration.Variables) - { - if (variable.Initializer != null) - { - var instantiatedType = context.SemanticModel.GetTypeInfo(variable.Initializer.Value); - AddVtableAttributesForType(instantiatedType, namedType); - } - } - } - } - else if (context.Node is PropertyDeclarationSyntax propertyDeclaration) - { - // Detect scenarios where the property declaration has an initializer and is to a boxed or cast type during initialization. - if (propertyDeclaration.Initializer != null) - { - var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol; - if (leftSymbol is INamedTypeSymbol namedType) - { - var instantiatedType = context.SemanticModel.GetTypeInfo(propertyDeclaration.Initializer.Value); - AddVtableAttributesForType(instantiatedType, namedType); - } - } - else if (propertyDeclaration.ExpressionBody != null) - { - var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol; - if (leftSymbol is INamedTypeSymbol namedType) - { - var instantiatedType = context.SemanticModel.GetTypeInfo(propertyDeclaration.ExpressionBody.Expression); - AddVtableAttributesForType(instantiatedType, namedType); - } - } - } - else if (context.Node is ReturnStatementSyntax { Expression: not null } returnDeclaration) - { - // Detect scenarios where the method or property being returned from is doing a box or cast of the type - // in the return statement. - var returnSymbol = context.SemanticModel.GetTypeInfo(returnDeclaration.Expression); - var parent = returnDeclaration.Ancestors().OfType().FirstOrDefault(); - if (parent is MethodDeclarationSyntax methodDeclaration) - { - var methodReturnSymbol = context.SemanticModel.GetSymbolInfo(methodDeclaration.ReturnType).Symbol; - if (methodReturnSymbol is ITypeSymbol typeSymbol) - { - AddVtableAttributesForType(returnSymbol, typeSymbol); - } - } - else if (parent is BasePropertyDeclarationSyntax propertyDeclarationSyntax) - { - var propertyTypeSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclarationSyntax.Type).Symbol; - if (propertyTypeSymbol is ITypeSymbol typeSymbol) - { - AddVtableAttributesForType(returnSymbol, typeSymbol); - } - } - } - else if (context.Node is CollectionExpressionSyntax collectionExpression) - { - // Detect collection expressions scenarios targeting interfaces, where we can rely on the concrete type - if (context.SemanticModel.GetOperation(collectionExpression) is ICollectionExpressionOperation operation && - operation.Type is INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true, IsUnboundGenericType: false, ConstructedFrom: not null } collectionType) - { - // Case 1: empty collection expression targeting 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList'. - // In this case, we can rely on Roslyn using an empty array. So let's pretend we saw it, and gather it for lookups. - if (operation.Elements.IsEmpty && - collectionType.ConstructedFrom.SpecialType is - SpecialType.System_Collections_Generic_IEnumerable_T or - SpecialType.System_Collections_Generic_IReadOnlyCollection_T or - SpecialType.System_Collections_Generic_IReadOnlyList_T) - { - IArrayTypeSymbol arrayTypeSymbol = context.SemanticModel.Compilation.CreateArrayTypeSymbol(collectionType.TypeArguments[0], rank: 1); - - AddVtableAttributesForTypeDirect(arrayTypeSymbol, null, collectionType); - } - else if (collectionType.ConstructedFrom.SpecialType is SpecialType.System_Collections_Generic_ICollection_T or SpecialType.System_Collections_Generic_IList_T) - { - // Case 2: a collection expression (empty or not) targeting 'ICollection' or 'IList'. - // In this case, Roslyn guarantees that 'List' will be used, so we can gather that type. - INamedTypeSymbol listOfTSymbol = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Collections.Generic.List`1")!; - INamedTypeSymbol constructedListSymbol = listOfTSymbol.Construct(collectionType.TypeArguments[0]); - - AddVtableAttributesForTypeDirect(constructedListSymbol, null, collectionType); - } - } - } - - return vtableAttributes.ToImmutableArray(); - - // Helper to directly use 'AddVtableAttributesForTypeDirect' with 'TypeInfo' values - void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType, ITypeSymbol convertedToTypeSymbol) - { - AddVtableAttributesForTypeDirect(instantiatedType.Type, instantiatedType.ConvertedType, convertedToTypeSymbol); - } - - // This handles adding vtable information for types for which we can not directly put an attribute on them. - // This includes generic types that are boxed and and non-WinRT types for which our AOT source generator hasn't - // ran on but implements WinRT interfaces. - void AddVtableAttributesForTypeDirect(ITypeSymbol instantiatedTypeSymbol, ITypeSymbol instantiatedConvertedTypeSymbol, ITypeSymbol convertedToTypeSymbol) - { - // This handles the case where there is an WinRT array possibly being assigned - // to an object type or a list. In this case, the IList interfaces of the array - // type need to be put on the CCW. - if (instantiatedTypeSymbol is IArrayTypeSymbol arrayType) - { - if (convertedToTypeSymbol is not IArrayTypeSymbol && - // Make sure we aren't just assigning it to a value type such as ReadOnlySpan - !convertedToTypeSymbol.IsValueType) - { - if (visitedTypes.Contains(arrayType)) - { - return; - } - visitedTypes.Add(arrayType); - - var vtableAtribute = GetVtableAttributeToAdd(arrayType, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); - if (vtableAtribute != default) - { - vtableAttributes.Add(vtableAtribute); - } - - // Also add the enumerator type to the lookup table as the native caller can call it. - AddEnumeratorAdapterForType(arrayType.ElementType, typeMapper, context.SemanticModel.Compilation, isManagedOnlyType, isWinRTType, vtableAttributes); - } - } - else if (instantiatedTypeSymbol is not null || instantiatedConvertedTypeSymbol is not null) - { - // Type might be null such as for lambdas, so check converted type in that case. - instantiatedTypeSymbol ??= instantiatedConvertedTypeSymbol; - - if (visitedTypes.Contains(instantiatedTypeSymbol)) - { - return; - } - visitedTypes.Add(instantiatedTypeSymbol); - - // This handles the case where a generic delegate is passed to a parameter - // statically declared as an object and thereby we won't be able to detect - // its actual type and handle it at compile time within the generated projection. - // When it is not declared as an object parameter but rather the generic delegate - // type itself, the generated marshaler code in the function makes sure the vtable - // information is available. - if (instantiatedTypeSymbol.TypeKind == TypeKind.Delegate && - instantiatedTypeSymbol.MetadataName.Contains("`") && - isWinRTType(instantiatedTypeSymbol, typeMapper) && - convertedToTypeSymbol.SpecialType == SpecialType.System_Object) - { - var argumentClassNamedTypeSymbol = instantiatedTypeSymbol as INamedTypeSymbol; - var vtableAtribute = GetVtableAttributeToAdd(instantiatedTypeSymbol, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); - if (vtableAtribute != default) - { - vtableAttributes.Add(vtableAtribute); - } - } - - // This handles the case where the source generator wasn't able to run - // and put the WinRTExposedType attribute on the class. This can be in the - // scenario where the caller defined their own generic class and - // pass it as a parameter. With generic classes, the interface itself - // might be generic too and due to that we handle it here. - // This also handles the case where the type being passed is from a different - // library which happened to not run the AOT optimizer. So as a best effort, - // we handle it here. - if (instantiatedTypeSymbol.TypeKind == TypeKind.Class) - { - bool addClassOnLookupTable = false; - if (instantiatedTypeSymbol.MetadataName.Contains("`")) - { - addClassOnLookupTable = - !GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) && - // If the type is defined in the same assembly as what the source generator is running on, - // we let the WinRTExposedType attribute generator handle it. The only scenario the generator - // doesn't handle which we handle here is if it is a generic type implementing generic WinRT interfaces. - (!SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) || - GeneratorHelper.HasNonInstantiatedWinRTGeneric(instantiatedTypeSymbol.OriginalDefinition, typeMapper)) && - // Make sure the type we are passing is being boxed or cast to another interface. - !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol); - } - else if (!isWinRTType(instantiatedTypeSymbol, typeMapper)) - { - addClassOnLookupTable = - !GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) && - // If the type is defined in the same assembly as what the source generator is running on, - // we let the WinRTExposedType attribute generator handle it. - !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) && - // Make sure the type we are passing is being boxed or cast to another interface. - !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol); - } - - if (addClassOnLookupTable) - { - var vtableAtribute = GetVtableAttributeToAdd(instantiatedTypeSymbol, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); - if (vtableAtribute != default) - { - vtableAttributes.Add(vtableAtribute); - } - - AddVtableAdapterTypeForKnownInterface(instantiatedTypeSymbol, context.SemanticModel.Compilation, isManagedOnlyType, isWinRTType, typeMapper, vtableAttributes); - } - } - } - } - } - - private static EquatableArray GetVtableAttributesToAddOnLookupTable( - GeneratorAttributeSyntaxContext context, - TypeMapper typeMapper, - bool isCsWinRTComponent) - { - var isManagedOnlyType = GeneratorHelper.IsManagedOnlyType(context.SemanticModel.Compilation); - var isWinRTType = GeneratorHelper.IsWinRTType(context.SemanticModel.Compilation, isCsWinRTComponent); - HashSet vtableAttributes = new(); - - foreach (var attributeData in context.Attributes) - { - if (attributeData.ConstructorArguments is [{ Kind: TypedConstantKind.Type, Value : ITypeSymbol vtableType }]) - { - if (vtableType is IArrayTypeSymbol arrayType) - { - var vtableAtribute = GetVtableAttributeToAdd(arrayType, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); - if (vtableAtribute != default) - { - vtableAttributes.Add(vtableAtribute); - } - - // Also add the enumerator type to the lookup table as the native caller can call it. - AddEnumeratorAdapterForType(arrayType.ElementType, typeMapper, context.SemanticModel.Compilation, isManagedOnlyType, isWinRTType, vtableAttributes); - } - else - { - var vtableAtribute = GetVtableAttributeToAdd(vtableType, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); - if (vtableAtribute != default) - { - vtableAttributes.Add(vtableAtribute); - } - - AddVtableAdapterTypeForKnownInterface(vtableType, context.SemanticModel.Compilation, isManagedOnlyType, isWinRTType, typeMapper, vtableAttributes); - } - } - } - - return vtableAttributes.ToImmutableArray(); - } - - // Any of the IEnumerable interfaces on the vtable can be used to get the enumerator. Given IEnumerable is - // a covariant interface, it means that we can end up getting an instance of the enumerable adapter for any one - // of those covariant interfaces and thereby need vtable lookup entries for all of them. - private static void AddEnumeratorAdapterForType( - ITypeSymbol type, - TypeMapper mapper, - Compilation compilation, - Func isManagedOnlyType, - Func isWinRTType, - HashSet vtableAttributes) - { - var enumerableType = compilation.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1"); - if (enumerableType != null) - { - var constructedEnumerableType = enumerableType.Construct(type); - if (TryGetCompatibleWindowsRuntimeTypesForVariantType(constructedEnumerableType, mapper, null, isWinRTType, out var compatibleIfaces)) - { - foreach (var compatibleIface in compatibleIfaces) - { - if (compatibleIface.MetadataName == "IEnumerable`1" && - !GeneratorHelper.IsInternalInterfaceFromReferences(compatibleIface, compilation.Assembly)) - { - var enumeratorAdapterType = compilation.GetTypeByMetadataName("ABI.System.Collections.Generic.ToAbiEnumeratorAdapter`1"); - if (enumeratorAdapterType != null) - { - var constructedEnumeratorAdapterType = enumeratorAdapterType.Construct(compatibleIface.TypeArguments[0]); - var vtableAttribute = GetVtableAttributeToAdd(constructedEnumeratorAdapterType, isManagedOnlyType, isWinRTType, mapper, compilation, false); - if (vtableAttribute != default) - { - vtableAttributes.Add(vtableAttribute); - } - } - } - } - } - } - } - - internal static void AddVtableAdapterTypeForKnownInterface( - ITypeSymbol classType, - Compilation compilation, - Func isManagedOnlyType, - Func isWinRTType, - TypeMapper mapper, - HashSet vtableAttributes) - { - // If the type is blocked for marshalling, don't generate any code for any interfaces - if (isManagedOnlyType(classType)) - { - return; - } - - foreach (var iface in classType.AllInterfaces) - { - if (iface.MetadataName == "IEnumerable`1") - { - AddEnumeratorAdapterForType(iface.TypeArguments[0], mapper, compilation, isManagedOnlyType, isWinRTType, vtableAttributes); - } - else if (iface.MetadataName == "IDictionary`2") - { - LookupAndAddVtableAttributeForGenericType("System.Collections.ObjectModel.ReadOnlyDictionary`2", iface.TypeArguments); - LookupAndAddVtableAttributeForGenericType("System.Collections.Generic.KeyValuePair`2", iface.TypeArguments); - LookupAndAddVtableAttributeForGenericType("ABI.System.Collections.Generic.ConstantSplittableMap`2", iface.TypeArguments); - } - else if (iface.MetadataName == "IList`1") - { - LookupAndAddVtableAttributeForGenericType("System.Collections.ObjectModel.ReadOnlyCollection`1", iface.TypeArguments); - } - } - - if (classType is INamedTypeSymbol namedType && IsDerivedFromOrIsObservableCollection(namedType)) - { - // ObservableCollection make use of two internal built-in types as part of its - // implementation for INotifyPropertyChanged. Handling those manually here. - var genericInterfaces = new List() { "System.Collections.IList", "System.Collections.IEnumerable" }; - var mapping = mapper.GetMappedType("System.Collections.IList").GetMapping(); - var runtimeClassName = mapping.Item1 + "." + mapping.Item2; - - // System.Collections.Specialized.ReadOnlyList - vtableAttributes.Add( - new VtableAttribute( - "System.Collections.Specialized", - false, - "ReadOnlyList", - ImmutableArray.Empty, - "System.Collections.Specialized.ReadOnlyList", - genericInterfaces.ToImmutableArray(), - ImmutableArray.Empty, - false, - false, - false, - runtimeClassName)); - - // System.Collections.Specialized.SingleItemReadOnlyList - vtableAttributes.Add( - new VtableAttribute( - "System.Collections.Specialized", - false, - "SingleItemReadOnlyList", - ImmutableArray.Empty, - "System.Collections.Specialized.SingleItemReadOnlyList", - genericInterfaces.ToImmutableArray(), - ImmutableArray.Empty, - false, - false, - false, - runtimeClassName)); - } - - void LookupAndAddVtableAttributeForGenericType(string type, ImmutableArray genericArgs) - { - var genericType = compilation.GetTypeByMetadataName(type); - if (genericType != default) - { - var constructedGenericType = genericType.Construct([.. genericArgs]); - var vtableAttribute = GetVtableAttributeToAdd(constructedGenericType, isManagedOnlyType, isWinRTType, mapper, compilation, false); - if (vtableAttribute != default) - { - vtableAttributes.Add(vtableAttribute); - } - } - } - - bool IsDerivedFromOrIsObservableCollection(INamedTypeSymbol namedType) - { - return namedType.MetadataName == "ObservableCollection`1" || - (namedType.BaseType is not null && IsDerivedFromOrIsObservableCollection(namedType.BaseType)); - } - } - - private static void GenerateVtableLookupTable( - SourceProductionContext sourceProductionContext, - (ImmutableArray vtableAttributes, (CsWinRTAotOptimizerProperties properties, string)) value) - { - GenerateVtableLookupTable(sourceProductionContext.AddSource, value); - } - - internal static void GenerateVtableLookupTable( - Action addSource, - (ImmutableArray vtableAttributes, (CsWinRTAotOptimizerProperties properties, string escapedAssemblyName) context) value, - bool isComponentGenerator = false) - { - if (!value.context.properties.IsCsWinRTAotOptimizerEnabled || !value.context.properties.IsCsWinRTCcwLookupTableGeneratorEnabled) - { - return; - } - - StringBuilder source = new(); - string classPrefix = isComponentGenerator ? "Authoring" : ""; - - // The generated lookup table is based on lookup by string rather than type to avoid 2 different issues: - // - // 1) We can run into nested private types in generics which we can't reference from here but still need to be able to create the vtable for. - // 2) While looking for a type in the lookup table, you can trigger module initializers for other modules - // referenced and that can run into issues because they can have their own lookup tables that - // get registered in their module initializer, but will fail to due to the reader writer lock we have around it - // (i.e. we are traversing the lookup tables here while one is being registered). - // - // Note: just like with the authoring metadata function, we don't use a method group expression but rather construct a 'Func' ourselves. - // This is done to opt-out of the implicit caching that Roslyn does. We don't need that extra code and overhead, as this is only done once. - var hasRuntimeClasNameEntries = value.vtableAttributes.Any(static v => !string.IsNullOrEmpty(v.RuntimeClassName)); - if (value.vtableAttributes.Any()) - { - source.AppendLine($$""" - using System; - using System.Runtime.InteropServices; - using System.Runtime.CompilerServices; - - namespace WinRT.{{value.context.escapedAssemblyName}}GenericHelpers - { - - internal static class {{classPrefix}}GlobalVtableLookup - { - - [System.Runtime.CompilerServices.ModuleInitializer] - internal static void InitializeGlobalVtableLookup() - { - ComWrappersSupport.RegisterTypeComInterfaceEntriesLookup(new Func(LookupVtableEntries)); - {{(hasRuntimeClasNameEntries ? "ComWrappersSupport.RegisterTypeRuntimeClassNameLookup(new Func(LookupRuntimeClassName));" : "")}} - } - - private static ComWrappers.ComInterfaceEntry[] LookupVtableEntries(Type type) - { - string typeName = type.ToString(); - """); - } - - // We gather all the class names that have the same vtable and generate it - // as part of one if to reduce generated code. - var vtableEntryToClassNameList = new Dictionary>(); - foreach (var vtableAttribute in value.vtableAttributes.ToImmutableHashSet()) - { - VtableEntry entry = new(vtableAttribute.Interfaces, vtableAttribute.GenericInterfaces, vtableAttribute.IsDelegate); - if (!vtableEntryToClassNameList.TryGetValue(entry, out var classNameList)) - { - classNameList = new List(); - vtableEntryToClassNameList.Add(entry, classNameList); - } - classNameList.Add(vtableAttribute.VtableLookupClassName); - } - - foreach (var vtableEntry in vtableEntryToClassNameList) - { - source.AppendLine($$""" - if (typeName == "{{vtableEntry.Value[0]}}" - """); - - for (var i = 1; i < vtableEntry.Value.Count; i++) - { - source.AppendLine($$""" - || typeName == "{{vtableEntry.Value[i]}}" - """); - } - - source.AppendLine($$""" - ) - { - {{GenerateVtableEntry(vtableEntry.Key, value.context.escapedAssemblyName)}} - } - """); - } - - if (value.vtableAttributes.Any()) - { - source.AppendLine($$""" - return default; - } - """); - - if (hasRuntimeClasNameEntries) - { - source.AppendLine($$""" - private static string LookupRuntimeClassName(Type type) - { - string typeName = type.ToString(); - """); - - var runtimeClassNameToClassNameList = new Dictionary>(); - foreach (var vtableAttribute in value.vtableAttributes.ToImmutableHashSet().Where(static v => !string.IsNullOrEmpty(v.RuntimeClassName))) - { - if (!runtimeClassNameToClassNameList.TryGetValue(vtableAttribute.RuntimeClassName, out var classNameList)) - { - classNameList = new List(); - runtimeClassNameToClassNameList.Add(vtableAttribute.RuntimeClassName, classNameList); - } - classNameList.Add(vtableAttribute.VtableLookupClassName); - } - - foreach (var entry in runtimeClassNameToClassNameList) - { - source.AppendLine($$""" - if (typeName == "{{entry.Value[0]}}" - """); - - for (var i = 1; i < entry.Value.Count; i++) - { - source.AppendLine($$""" - || typeName == "{{entry.Value[i]}}" - """); - } - - source.AppendLine($$""" - ) - { - return "{{entry.Key}}"; - } - """); - } - - source.AppendLine($$""" - return default; - } - """); - } - - source.AppendLine($$""" - } - } - """); - addSource($"WinRT{classPrefix}GlobalVtableLookup.g.cs", source.ToString()); - } - } - - private static void GenerateBindableCustomProperties( - SourceProductionContext sourceProductionContext, - (ImmutableArray bindableCustomProperties, CsWinRTAotOptimizerProperties properties) value) - { - if (!value.properties.IsCsWinRTAotOptimizerEnabled || value.bindableCustomProperties.Length == 0) - { - return; - } - - StringBuilder source = new(); - - foreach (var bindableCustomProperties in value.bindableCustomProperties) - { - if (!bindableCustomProperties.IsGlobalNamespace) - { - source.AppendLine($$""" - namespace {{bindableCustomProperties.Namespace}} - { - """); - } - - var escapedClassName = GeneratorHelper.EscapeTypeNameForIdentifier(bindableCustomProperties.TypeName); - - ReadOnlySpan classHierarchy = bindableCustomProperties.ClassHierarchy.AsSpan(); - // If the type is nested, correctly nest the type definition - for (int i = classHierarchy.Length - 1; i > 0; i--) - { - source.AppendLine($$""" - partial {{classHierarchy[i].GetTypeKeyword()}} {{classHierarchy[i].QualifiedName}} - { - """); - } - - string typeKeyword = TypeInfo.GetTypeKeyword(bindableCustomProperties.TypeKind, bindableCustomProperties.IsRecord); - - source.AppendLine($$""" - partial {{typeKeyword}} {{(classHierarchy.IsEmpty ? bindableCustomProperties.TypeName : classHierarchy[0].QualifiedName)}} : global::Microsoft.UI.Xaml.Data.IBindableCustomPropertyImplementation - { - global::Microsoft.UI.Xaml.Data.BindableCustomProperty global::Microsoft.UI.Xaml.Data.IBindableCustomPropertyImplementation.GetProperty(string name) - { - """); - - foreach (var property in bindableCustomProperties.Properties.Where(static p => !p.IsIndexer)) - { - var instanceAccessor = property.IsStatic ? bindableCustomProperties.QualifiedClassName : $$"""(({{bindableCustomProperties.QualifiedClassName}})instance)"""; - - source.AppendLine($$""" - if (name == "{{property.Name}}") - { - return new global::Microsoft.UI.Xaml.Data.BindableCustomProperty( - {{GetBoolAsString(property.CanRead)}}, - {{GetBoolAsString(property.CanWrite)}}, - "{{property.Name}}", - typeof({{property.Type}}), - {{ (property.CanRead ? $$"""static (instance) => {{instanceAccessor}}.{{property.Name}}""" : "null") }}, - {{ (property.CanWrite ? $$"""static (instance, value) => {{instanceAccessor}}.{{property.Name}} = ({{property.Type}})value""" : "null") }}, - null, - null); - } - """); - } - - source.AppendLine($$""" - return default; - } - - global::Microsoft.UI.Xaml.Data.BindableCustomProperty global::Microsoft.UI.Xaml.Data.IBindableCustomPropertyImplementation.GetProperty(global::System.Type indexParameterType) - { - """); - - foreach (var property in bindableCustomProperties.Properties.Where(static p => p.IsIndexer)) - { - var instanceAccessor = property.IsStatic ? bindableCustomProperties.QualifiedClassName : $$"""(({{bindableCustomProperties.QualifiedClassName}})instance)"""; - - source.AppendLine($$""" - if (indexParameterType == typeof({{property.IndexerType}})) - { - return new global::Microsoft.UI.Xaml.Data.BindableCustomProperty( - {{GetBoolAsString(property.CanRead)}}, - {{GetBoolAsString(property.CanWrite)}}, - "{{property.Name}}", - typeof({{property.Type}}), - null, - null, - {{ (property.CanRead ? $$"""static (instance, index) => {{instanceAccessor}}[({{property.IndexerType}})index]""" : "null") }}, - {{ (property.CanWrite ? $$"""static (instance, value, index) => {{instanceAccessor}}[({{property.IndexerType}})index] = ({{property.Type}})value""" : "null") }}); - } - """); - } - - source.AppendLine($$""" - return default; - } - } - """); - - // Close all brackets - for (int i = classHierarchy.Length - 1; i > 0; i--) - { - source.AppendLine("}"); - } - - if (!bindableCustomProperties.IsGlobalNamespace) - { - source.AppendLine($@"}}"); - } - - source.AppendLine(); - } - - sourceProductionContext.AddSource("WinRTCustomBindableProperties.g.cs", source.ToString()); - - static string GetBoolAsString(bool value) => value ? "true" : "false"; - } - } - - internal readonly record struct GenericParameter( - string ProjectedType, - string AbiType, - TypeKind TypeKind); - - internal readonly record struct GenericInterface( - string Interface, - string GenericDefinition, - EquatableArray GenericParameters); - - internal sealed record VtableAttribute( - string Namespace, - bool IsGlobalNamespace, - string ClassName, - EquatableArray ClassHierarchy, - string VtableLookupClassName, - EquatableArray Interfaces, - EquatableArray GenericInterfaces, - bool IsArray, - bool IsDelegate, - bool IsPublic, - string RuntimeClassName = default); - - sealed record VtableEntry( - EquatableArray Interfaces, - EquatableArray GenericInterfaces, - bool IsDelegate); - - internal readonly record struct BindableCustomProperty( - string Name, - string Type, - bool CanRead, - bool CanWrite, - bool IsIndexer, - string IndexerType, - bool IsStatic); - - internal readonly record struct BindableCustomProperties( - string Namespace, - bool IsGlobalNamespace, - string TypeName, - TypeKind TypeKind, - bool IsRecord, - EquatableArray ClassHierarchy, - string QualifiedClassName, - EquatableArray Properties); - - internal readonly record struct CsWinRTAotOptimizerProperties( - bool IsCsWinRTAotOptimizerEnabled, - bool IsCsWinRTComponent, - bool IsCsWinRTCcwLookupTableGeneratorEnabled, - bool IsCsWinRTAotOptimizerInAutoMode); - - /// - /// A model describing a type info in a type hierarchy. - /// - /// The qualified name for the type. - /// The kind of the type in the hierarchy. - /// Whether the type is a record type. - // Ported from https://github.com/Sergio0694/ComputeSharp - internal sealed record TypeInfo(string QualifiedName, TypeKind Kind, bool IsRecord) - { - /// - /// Gets the keyword for the current type kind. - /// - /// The keyword for the current type kind. - public string GetTypeKeyword() - { - return GetTypeKeyword(Kind, IsRecord); - } - - /// - /// Gets the keyword for a given kind and record option. - /// - /// The type kind. - /// Whether the type is a record. - /// The keyword for a given kind and record option. - public static string GetTypeKeyword(TypeKind kind, bool isRecord) - { - return kind switch - { - TypeKind.Struct when isRecord => "record struct", - TypeKind.Struct => "struct", - TypeKind.Interface => "interface", - TypeKind.Class when isRecord => "record", - _ => "class" - }; - } - } -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading; +using WinRT.SourceGenerator; + +namespace Generator +{ + [Generator] + public class WinRTAotSourceGenerator : IIncrementalGenerator + { + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var properties = context.AnalyzerConfigOptionsProvider + .Combine(context.CompilationProvider) + .Select(static ((AnalyzerConfigOptionsProvider provider, Compilation compilation) value, CancellationToken _) => + new CsWinRTAotOptimizerProperties( + value.provider.IsCsWinRTAotOptimizerEnabled(), + value.provider.IsCsWinRTComponent(), + value.provider.IsCsWinRTCcwLookupTableGeneratorEnabled(), + GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(value.provider, value.compilation)) + ); + + var assemblyName = context.CompilationProvider.Select(static (compilation, _) => GeneratorHelper.EscapeAssemblyNameForIdentifier(compilation.AssemblyName)); + + var propertiesAndAssemblyName = properties.Combine(assemblyName); + + var typeMapperAndProperties = context.AnalyzerConfigOptionsProvider + .Select(static (options, ct) => options.GetCsWinRTUseWindowsUIXamlProjections()) + .Select(static (mode, ct) => new TypeMapper(mode)) + .Combine(properties); + + var vtablesToAddFromDetectedClassTypes = context.SyntaxProvider.CreateSyntaxProvider( + static (n, _) => NeedVtableAttribute(n), + static (n, _) => n) + .Combine(typeMapperAndProperties) + .Select(static ((GeneratorSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, CancellationToken _) => + value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerInAutoMode ? + GetVtableAttributeToAdd(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, false, value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled) : default) + .Where(static vtableAttribute => vtableAttribute != default); + + var autoDetectedVtableAttributesToAdd = vtablesToAddFromDetectedClassTypes.Select(static (vtable, _) => vtable.Item1); + var autoDetectedAdapterTypesToAddOnLookupTable = vtablesToAddFromDetectedClassTypes.SelectMany(static (vtable, _) => vtable.Item2); + + var vtablesToAddFromOptInClassTypes = context.SyntaxProvider.ForAttributeWithMetadataName( + "WinRT.GeneratedWinRTExposedTypeAttribute", + static (n, _) => NeedVtableAttribute(n), + static (n, _) => n) + .Combine(typeMapperAndProperties) + .Select(static ((GeneratorAttributeSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, CancellationToken _) => + value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerEnabled ? + GetVtableAttributeToAdd(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, false, value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled) : default) + .Where(static vtableAttribute => vtableAttribute != default); + + var optinVtableAttributesToAdd = vtablesToAddFromOptInClassTypes.Select(static (vtable, _) => vtable.Item1); + var optinAdapterTypesToAddOnLookupTable = vtablesToAddFromOptInClassTypes.SelectMany(static (vtable, _) => vtable.Item2); + + // Merge both auto detected vtables and opt-in vtables. + var vtableAttributesToAdd = autoDetectedVtableAttributesToAdd.Collect().Combine(optinVtableAttributesToAdd.Collect()).SelectMany(static (value, _) => value.Left.AddRange(value.Right).Distinct()); + context.RegisterImplementationSourceOutput(vtableAttributesToAdd.Collect().Combine(propertiesAndAssemblyName), GenerateVtableAttributes); + + // Get the vtables for component types. This is used for filtering out generic interfaces + // that will already be generated by the component generator. + var vtablesFromComponentTypes = context.SyntaxProvider.CreateSyntaxProvider( + static (n, _) => IsComponentType(n), + static (n, _) => n) + .Combine(typeMapperAndProperties) + // Get component types if only authoring scenario and if aot optimizer enabled. + .Select(static ((GeneratorSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, CancellationToken _) => + value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerEnabled && value.typeMapperAndProperties.properties.IsCsWinRTComponent ? + GetVtableAttributeToAdd(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, true, true) : default) + .Where(static vtableAttribute => vtableAttribute != default); + + var autoDetectedInstantiatedTypesToAddOnLookupTable = context.SyntaxProvider.CreateSyntaxProvider( + static (n, _) => NeedVtableOnLookupTable(n), + static (n, _) => n) + .Combine(typeMapperAndProperties) + .Select(static ((GeneratorSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, + CancellationToken _) => + value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerInAutoMode && value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled ? + GetVtableAttributesToAddOnLookupTable(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, value.typeMapperAndProperties.properties.IsCsWinRTComponent) : + (EquatableArray)ImmutableArray.Empty) + .SelectMany(static (vtable, _) => vtable) + .Where(static vtableAttribute => vtableAttribute != null); + + var optinInstantiatedTypesToAddOnLookupTable = context.SyntaxProvider.ForAttributeWithMetadataName( + "WinRT.GeneratedWinRTExposedExternalTypeAttribute", + static (n, _) => true, + static (n, _) => n) + .Combine(typeMapperAndProperties) + .Select(static ((GeneratorAttributeSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, + CancellationToken _) => + value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerEnabled && value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled ? + GetVtableAttributesToAddOnLookupTable(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, value.typeMapperAndProperties.properties.IsCsWinRTComponent) : + (EquatableArray)ImmutableArray.Empty) + .SelectMany(static (vtable, _) => vtable) + .Where(static vtableAttribute => vtableAttribute != null); + + var instantiatedTaskAdapters = context.SyntaxProvider.CreateSyntaxProvider( + static (n, _) => IsAsyncOperationMethodCall(n), + static (n, _) => n) + .Combine(typeMapperAndProperties) + .Select(static ((GeneratorSyntaxContext generatorSyntaxContext, (TypeMapper typeMapper, CsWinRTAotOptimizerProperties properties) typeMapperAndProperties) value, + CancellationToken _) => + value.typeMapperAndProperties.properties.IsCsWinRTAotOptimizerInAutoMode && value.typeMapperAndProperties.properties.IsCsWinRTCcwLookupTableGeneratorEnabled ? + GetVtableAttributesForTaskAdapters(value.generatorSyntaxContext, value.typeMapperAndProperties.typeMapper, value.typeMapperAndProperties.properties.IsCsWinRTComponent) : default) + .Where(static vtableAttribute => vtableAttribute != default) + .Collect(); + + // Merge both adapter types lists and instantiated types lists. + var vtablesToAddOnLookupTable = + autoDetectedInstantiatedTypesToAddOnLookupTable.Collect(). + Combine(autoDetectedAdapterTypesToAddOnLookupTable.Collect()). + Combine(optinInstantiatedTypesToAddOnLookupTable.Collect()). + Combine(optinAdapterTypesToAddOnLookupTable.Collect()). + Combine(instantiatedTaskAdapters). + SelectMany(static (value, _) => + value.Left.Left.Left.Left + .AddRange(value.Left.Left.Left.Right) + .AddRange(value.Left.Left.Right) + .AddRange(value.Left.Right) + .AddRange(value.Right) + .Distinct() + ); + + var genericInterfacesFromVtableAttribute = vtableAttributesToAdd.Combine(properties).SelectMany( + static ((VtableAttribute vtableAttribute, CsWinRTAotOptimizerProperties properties) value, CancellationToken _) => + // If this is a CsWinRT component, the public types are handled by the component source generator rather than + // the AOT source generator. So we filter those out here. + (!value.properties.IsCsWinRTComponent || (value.properties.IsCsWinRTComponent && !value.vtableAttribute.IsPublic)) ? + value.vtableAttribute.GenericInterfaces : (EquatableArray)ImmutableArray.Empty).Collect(); + var genericInterfacesFromVtableLookupTable = vtablesToAddOnLookupTable.SelectMany(static (vtable, _) => vtable.GenericInterfaces).Collect(); + + // The component generator generates vtable attributes for public types. The generic interfaces used by those types or its adapter types + // can overlap with the ones being generated here. So get which ones are already generated to be able to filter them out. + var genericInterfacesGeneratedByComponentGenerator = vtablesFromComponentTypes. + SelectMany(static ((VtableAttribute vtableAttribute, EquatableArray adapterTypes) classType, CancellationToken _) => + classType.vtableAttribute.GenericInterfaces.Union(classType.adapterTypes.SelectMany(static v => v.GenericInterfaces)).Distinct()). + Collect(); + + context.RegisterImplementationSourceOutput( + genericInterfacesFromVtableAttribute + .Combine(genericInterfacesFromVtableLookupTable) + .Combine(genericInterfacesGeneratedByComponentGenerator) + .Combine(propertiesAndAssemblyName), + GenerateCCWForGenericInstantiation); + + context.RegisterImplementationSourceOutput(vtablesToAddOnLookupTable.Collect().Combine(propertiesAndAssemblyName), GenerateVtableLookupTable); + + var bindableCustomPropertyAttributes = context.SyntaxProvider.ForAttributeWithMetadataName( + "WinRT.GeneratedBindableCustomPropertyAttribute", + static (n, _) => NeedCustomPropertyImplementation(n), + static (n, _) => n) + .Combine(properties) + .Select(static ((GeneratorAttributeSyntaxContext generatorSyntaxContext, CsWinRTAotOptimizerProperties properties) value, CancellationToken _) => + value.properties.IsCsWinRTAotOptimizerEnabled ? GetBindableCustomProperties(value.generatorSyntaxContext) : default) + .Where(static bindableCustomProperties => bindableCustomProperties != default) + .Collect() + .Combine(properties); + context.RegisterImplementationSourceOutput(bindableCustomPropertyAttributes, GenerateBindableCustomProperties); + } + + // Restrict to non-projected classes which can be instantiated + // and are partial allowing to add attributes. + private static bool NeedVtableAttribute(SyntaxNode node) + { + return node is ClassDeclarationSyntax declaration && + !declaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword) || m.IsKind(SyntaxKind.AbstractKeyword)) && + GeneratorHelper.IsPartial(declaration) && + !GeneratorHelper.IsWinRTType(declaration); // Making sure it isn't an RCW we are projecting. + } + + // Filters to non WinRT types which are public and can be instantiated. + // This is used to try to determine types which a component source generator will process. + private static bool IsComponentType(SyntaxNode node) + { + return node is ClassDeclarationSyntax declaration && + !declaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword) || m.IsKind(SyntaxKind.AbstractKeyword)) && + declaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.PublicKeyword)) && + !GeneratorHelper.IsWinRTType(declaration); // Making sure it isn't an RCW we are projecting. + } + + private static bool NeedCustomPropertyImplementation(SyntaxNode node) + { + if ((node is ClassDeclarationSyntax classDeclaration && !classDeclaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword) || m.IsKind(SyntaxKind.AbstractKeyword))) || + (node is RecordDeclarationSyntax recordDeclaration && !recordDeclaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword) || m.IsKind(SyntaxKind.AbstractKeyword))) || + (node is StructDeclarationSyntax structDeclaration && !structDeclaration.Modifiers.Any(static m => m.IsKind(SyntaxKind.StaticKeyword)))) + { + TypeDeclarationSyntax typeDeclaration = (TypeDeclarationSyntax)node; + + return GeneratorHelper.IsPartial(typeDeclaration); + } + + return false; + } + + private static (VtableAttribute, EquatableArray) GetVtableAttributeToAdd( + GeneratorSyntaxContext context, + TypeMapper typeMapper, + bool checkForComponentTypes, + bool isCsWinRTCcwLookupTableGeneratorEnabled) + { + return GetVtableAttributeToAdd( + context.SemanticModel.GetDeclaredSymbol(context.Node as ClassDeclarationSyntax), + typeMapper, + context.SemanticModel.Compilation, + checkForComponentTypes, + isCsWinRTCcwLookupTableGeneratorEnabled); + } + + private static (VtableAttribute, EquatableArray) GetVtableAttributeToAdd( + GeneratorAttributeSyntaxContext context, + TypeMapper typeMapper, + bool checkForComponentTypes, + bool isCsWinRTCcwLookupTableGeneratorEnabled) + { + return GetVtableAttributeToAdd( + (ITypeSymbol)context.TargetSymbol, + typeMapper, + context.SemanticModel.Compilation, + checkForComponentTypes, + isCsWinRTCcwLookupTableGeneratorEnabled); + } + + private static (VtableAttribute, EquatableArray) GetVtableAttributeToAdd( + ITypeSymbol symbol, + TypeMapper typeMapper, + Compilation compilation, + bool checkForComponentTypes, + bool isCsWinRTCcwLookupTableGeneratorEnabled) + { + var isManagedOnlyType = GeneratorHelper.IsManagedOnlyType(compilation); + var isWinRTTypeFunc = GeneratorHelper.IsWinRTType(compilation, checkForComponentTypes); + var vtableAttribute = GetVtableAttributeToAdd(symbol, isManagedOnlyType, isWinRTTypeFunc, typeMapper, compilation, false); + if (vtableAttribute != default) + { + HashSet vtableAttributesForLookupTable = []; + // Add any adapter types which may be needed if certain functions + // from some known interfaces are called. + if (isCsWinRTCcwLookupTableGeneratorEnabled) + { + AddVtableAdapterTypeForKnownInterface(symbol, compilation, isManagedOnlyType, isWinRTTypeFunc, typeMapper, vtableAttributesForLookupTable); + } + return (vtableAttribute, vtableAttributesForLookupTable.ToImmutableArray()); + } + + return default; + } + + // There are several async operation related methods that can be called. + // But they are all under the AsyncInfo static class or is the AsAsyncOperation + // extension method. + static bool IsAsyncOperationMethodCall(SyntaxNode node) + { + if (node is InvocationExpressionSyntax methodInvoke && + methodInvoke.Expression is MemberAccessExpressionSyntax methodAccess) + { + // Check for static class as a way of handling all the async functions from it. + if (methodAccess.Expression is IdentifierNameSyntax className && + className.Identifier.ValueText == "AsyncInfo") + { + return true; + } + + // Check for calling the fully qualified static class. + // i.e. System.Runtime.InteropServices.WindowsRuntime.AsyncInfo + if (methodAccess.Expression is MemberAccessExpressionSyntax memberAccess && + memberAccess.Name.Identifier.ValueText == "AsyncInfo") + { + return true; + } + + // Check for function call for the scenario that doesn't use the static class. + if (methodAccess.Name is IdentifierNameSyntax methodName) + { + return methodName.Identifier.ValueText == "AsAsyncOperation"; + } + } + + return false; + } + + // Detect if AsAsyncOperation or similar function is being called and if so, + // make sure the generic adapter type we use for it is on the lookup table. + // We do this both assuming this is not an authoring component and is an authoring + // component as we don't know that at this stage and the results can vary based on that. + // We will choose the right one later when we can combine with properties. + private static VtableAttribute GetVtableAttributesForTaskAdapters(GeneratorSyntaxContext context, TypeMapper typeMapper, bool isCsWinRTComponent) + { + // Generic instantiation of task adapters make of use of unsafe. + // This will be caught by GetVtableAttributeToAdd, but catching it early here too. + if (!GeneratorHelper.AllowUnsafe(context.SemanticModel.Compilation)) + { + return default; + } + + if (context.SemanticModel.GetSymbolInfo(context.Node as InvocationExpressionSyntax).Symbol is IMethodSymbol symbol) + { + var adapterTypeStr = GeneratorHelper.GetTaskAdapterIfAsyncMethod(symbol); + if (!string.IsNullOrEmpty(adapterTypeStr)) + { + var adpaterType = context.SemanticModel.Compilation.GetTypeByMetadataName(adapterTypeStr); + if (adpaterType is not null) + { + var constructedAdapterType = adpaterType.Construct([.. symbol.TypeArguments]); + return GetVtableAttributeToAdd( + constructedAdapterType, + GeneratorHelper.IsManagedOnlyType(context.SemanticModel.Compilation), + GeneratorHelper.IsWinRTType(context.SemanticModel.Compilation, isCsWinRTComponent), + typeMapper, + context.SemanticModel.Compilation, + false); + } + } + } + + return default; + } + +#nullable enable + private static BindableCustomProperties GetBindableCustomProperties(GeneratorAttributeSyntaxContext context) + { + // We expect a class with a single attribute. + var symbol = (INamedTypeSymbol)context.TargetSymbol; + var attributeData = context.Attributes.First(); + + List bindableCustomProperties = new(); + + // Make all public properties in the class bindable including ones in base type. + if (attributeData.ConstructorArguments.Length == 0) + { + for (var curSymbol = symbol; curSymbol != null; curSymbol = curSymbol.BaseType) + { + foreach (var propertySymbol in curSymbol.GetMembers(). + Where(static m => m.Kind == SymbolKind.Property && + m.DeclaredAccessibility == Accessibility.Public)) + { + AddProperty(propertySymbol); + } + } + } + // Make specified public properties in the class bindable including ones in base type. + else if (attributeData.ConstructorArguments is + [ + { Kind: TypedConstantKind.Array, Values: [..] propertyNames }, + { Kind: TypedConstantKind.Array, Values: [..] propertyIndexerTypes } + ]) + { + for (var curSymbol = symbol; curSymbol != null; curSymbol = curSymbol.BaseType) + { + foreach (var member in curSymbol.GetMembers()) + { + if (member is IPropertySymbol propertySymbol && + member.DeclaredAccessibility == Accessibility.Public) + { + if (!propertySymbol.IsIndexer && + propertyNames.Any(p => p.Value is string value && value == propertySymbol.Name)) + { + AddProperty(propertySymbol); + } + else if (propertySymbol.IsIndexer && + // ICustomProperty only supports single indexer parameter. + propertySymbol.Parameters.Length == 1 && + propertyIndexerTypes.Any(p => p.Value is ISymbol typeSymbol && typeSymbol.Equals(propertySymbol.Parameters[0].Type, SymbolEqualityComparer.Default))) + { + AddProperty(propertySymbol); + } + } + } + } + } + + var typeName = ToFullyQualifiedString(symbol); + bool isGlobalNamespace = symbol.ContainingNamespace == null || symbol.ContainingNamespace.IsGlobalNamespace; + var @namespace = symbol.ContainingNamespace?.ToDisplayString(); + if (!isGlobalNamespace) + { + typeName = typeName[(@namespace!.Length + 1)..]; + } + + EquatableArray classHierarchy = ImmutableArray.Empty; + + // Gather the type hierarchy, only if the type is nested (as an optimization) + if (symbol.ContainingType is not null) + { + List hierarchyList = new(); + + for (ITypeSymbol parent = symbol; parent is not null; parent = parent.ContainingType) + { + hierarchyList.Add(new TypeInfo( + parent.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), + parent.TypeKind, + parent.IsRecord)); + } + + classHierarchy = ImmutableArray.CreateRange(hierarchyList); + } + + return new BindableCustomProperties( + @namespace, + isGlobalNamespace, + typeName, + symbol.TypeKind, + symbol.IsRecord, + classHierarchy, + ToFullyQualifiedString(symbol), + bindableCustomProperties.ToImmutableArray()); + + void AddProperty(ISymbol symbol) + { + if (symbol is IPropertySymbol propertySymbol) + { + bindableCustomProperties.Add(new BindableCustomProperty( + propertySymbol.MetadataName, + ToFullyQualifiedString(propertySymbol.Type), + // Make sure the property accessors are also public even if property itself is public. + propertySymbol.GetMethod != null && propertySymbol.GetMethod.DeclaredAccessibility == Accessibility.Public, + propertySymbol.SetMethod != null && !propertySymbol.SetMethod.IsInitOnly && propertySymbol.SetMethod.DeclaredAccessibility == Accessibility.Public, + propertySymbol.IsIndexer, + propertySymbol.IsIndexer ? ToFullyQualifiedString(propertySymbol.Parameters[0].Type) : "", + propertySymbol.IsStatic + )); + } + } + } +#nullable disable + + private static string ToFullyQualifiedString(ISymbol symbol) + { + // Used to ensure class names within generics are fully qualified to avoid + // having issues when put in ABI namespaces. + var symbolDisplayString = new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes | SymbolDisplayMiscellaneousOptions.ExpandNullable); + + var qualifiedString = symbol.ToDisplayString(symbolDisplayString); + return qualifiedString.StartsWith("global::") ? qualifiedString[8..] : qualifiedString; + } + + private static string ToVtableLookupString(ISymbol symbol) + { + List genericArguments = []; + var fullName = ToVtableLookupString(symbol, genericArguments); + if (genericArguments.Count == 0) + { + return fullName; + } + + return $$"""{{fullName}}[{{string.Join(",", genericArguments)}}]"""; + } + + private static string ToVtableLookupString(ISymbol symbol, List genericArguments, bool ignoreTypeArguments = false) + { + if (symbol is INamedTypeSymbol namedTypeSymbol && + !ignoreTypeArguments && + namedTypeSymbol.TypeArguments.Length != 0) + { + // Ignore type arguments and get the string representation for the rest of + // the type to properly handle nested types. + var fullName = ToVtableLookupString(symbol, genericArguments, true); + // Type arguments are collected but not added to the type name until the end + // per the format of Type.ToString(). ToVtableLookupString on the symbol is + // also called first to ensure any type arguments from any nested parent types + // are added first. + foreach (var typeArgument in namedTypeSymbol.TypeArguments) + { + genericArguments.Add(ToVtableLookupString(typeArgument)); + } + return fullName; + } + else + { + // If it is a generic type argument or the type is directly under a namspace, we just use the ToDisplayString API. + if (symbol is not INamedTypeSymbol || symbol.ContainingSymbol is INamespaceSymbol || symbol.ContainingSymbol is null) + { + var arity = symbol is INamedTypeSymbol namedType && namedType.Arity > 0 ? "`" + namedType.Arity : ""; + var symbolDisplayString = new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + miscellaneousOptions: SymbolDisplayMiscellaneousOptions.ExpandNullable); + return symbol.ToDisplayString(symbolDisplayString) + arity; + } + else + { + // Nested types use + in the fully qualified name rather than . + return ToVtableLookupString(symbol.ContainingSymbol, genericArguments) + "+" + symbol.MetadataName; + } + } + } + + private static string GetRuntimeClassName( + INamedTypeSymbol type, + Func isWinRTType, + TypeMapper mapper) + { + if (type == null) + { + return string.Empty; + } + + string metadataName = string.Join(".", type.ContainingNamespace?.ToDisplayString(), type.MetadataName); + if (type.IsGenericType && !type.IsDefinition) + { + StringBuilder builder = new(); + + builder.Append(GetRuntimeClassName(type.OriginalDefinition, isWinRTType, mapper)); + builder.Append("<"); + + bool first = true; + foreach (var genericArg in type.TypeArguments) + { + if (!first) + { + builder.Append(", "); + } + + builder.Append(GetRuntimeClassName(genericArg as INamedTypeSymbol, isWinRTType, mapper)); + first = false; + } + + builder.Append(">"); + + return builder.ToString(); + } + else if (type.SpecialType == SpecialType.System_Object) + { + return "Object"; + } + else if (type.SpecialType == SpecialType.System_Byte) + { + return "UInt8"; + } + else if (type.SpecialType == SpecialType.System_SByte) + { + return "Int8"; + } + else if (mapper.HasMappingForType(metadataName)) + { + var mapping = mapper.GetMappedType(metadataName).GetMapping(); + return mapping.Item1 + "." + mapping.Item2; + } + else if (type.SpecialType != SpecialType.None) + { + return type.Name; + } + else if (isWinRTType(type, mapper)) + { + return metadataName; + } + else + { + // If we end up here, this is most likely an authoring scenario where the type is being authored + // for WinRT projection in this component. + return metadataName; + } + } + + internal static VtableAttribute GetVtableAttributeToAdd( + ITypeSymbol symbol, + Func isManagedOnlyType, + Func isWinRTType, + TypeMapper mapper, + Compilation compilation, + bool isAuthoring, + string authoringDefaultInterface = "") + { + if (symbol is null) + { + return default; + } + + if (GeneratorHelper.HasNonInstantiatedWinRTGeneric(symbol, mapper)) + { + return default; + } + + // Skip all types explicitly blocked for marshalling. + // We don't want them to affect the codegen at all. + if (isManagedOnlyType(symbol)) + { + return default; + } + + HashSet interfacesToAddToVtable = new(); + HashSet genericInterfacesToAddToVtable = new(); + + if (!string.IsNullOrEmpty(authoringDefaultInterface)) + { + interfacesToAddToVtable.Add(authoringDefaultInterface); + } + + // If the attribute is already placed on the type, don't generate a new one as we will + // use the specified one. Also for authoring scenarios where we call this for authored WinRT types, + // don't generate the runtimeclass name for them as we will rely on the full name for them as we do today. + var checkForRuntimeClasName = !GeneratorHelper.HasWinRTRuntimeClassNameAttribute(symbol, compilation) && + (!isAuthoring || (isAuthoring && !isWinRTType(symbol, mapper))); + INamedTypeSymbol interfaceToUseForRuntimeClassName = null; + foreach (var iface in symbol.AllInterfaces) + { + if (isWinRTType(iface, mapper)) + { + // If the interface projection was generated using an older CsWinRT version, + // it won't have the necessary properties to generate the AOT compatible code + // and we don't want to result in compiler errors. + // We exclude generic types as they are either defined in WinRT.Runtime or the + // Windows SDK projection, so we don't need to check them. + if (!iface.IsGenericType && + GeneratorHelper.IsOldProjectionAssembly(iface.ContainingAssembly)) + { + return default; + } + + interfacesToAddToVtable.Add(ToFullyQualifiedString(iface)); + AddGenericInterfaceInstantiation(iface); + CheckForInterfaceToUseForRuntimeClassName(iface); + } + + if (iface.IsGenericType && TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, mapper, null, isWinRTType, out var compatibleIfaces)) + { + foreach (var compatibleIface in compatibleIfaces) + { + // For covariant interfaces which are exclusive interfaces that the projection implemented + // such as overrides / protected interfaces in composable types, we don't include them in + // the vtable as they are today marked internal and we can't reference them due to that. + // If this scenarios matters where native callers do indeed QI for these exclusive + // covariant interfaces, we can in the future project them as public, but for now + // leaving as is. + if (GeneratorHelper.IsInternalInterfaceFromReferences(compatibleIface, compilation.Assembly)) + { + continue; + } + + interfacesToAddToVtable.Add(ToFullyQualifiedString(compatibleIface)); + AddGenericInterfaceInstantiation(compatibleIface); + CheckForInterfaceToUseForRuntimeClassName(compatibleIface); + } + } + } + + // KeyValueType is a value type in C#, but it is projected as a reference type in WinRT. + if (symbol.TypeKind == TypeKind.Struct && symbol.MetadataName == "KeyValuePair`2" && isWinRTType(symbol, mapper)) + { + interfacesToAddToVtable.Add(ToFullyQualifiedString(symbol)); + AddGenericInterfaceInstantiation(symbol as INamedTypeSymbol); + + // KeyValuePair is projected as an interface. + CheckForInterfaceToUseForRuntimeClassName(symbol as INamedTypeSymbol); + } + + bool isDelegate = false; + if (symbol.TypeKind == TypeKind.Delegate) + { + isDelegate = true; + interfacesToAddToVtable.Add(ToFullyQualifiedString(symbol)); + AddGenericInterfaceInstantiation(symbol as INamedTypeSymbol); + } + + if (!interfacesToAddToVtable.Any()) + { + return default; + } + + // If there are generic interfaces, the generic interface instantiations make use of + // unsafe. But if it isn't enabled, we don't want to fail to compile in case it is + // not a WinRT scenario. So we instead, don't generate the code that needs the unsafe + // and there would be a diagnostic produced by the analyzer. + if (genericInterfacesToAddToVtable.Any() && !GeneratorHelper.AllowUnsafe(compilation)) + { + return default; + } + + var typeName = ToFullyQualifiedString(symbol); + bool isGlobalNamespace = symbol.ContainingNamespace == null || symbol.ContainingNamespace.IsGlobalNamespace; + var @namespace = symbol.ContainingNamespace?.ToDisplayString(); + if (!isGlobalNamespace) + { + typeName = typeName[(@namespace.Length + 1)..]; + } + + EquatableArray classHierarchy = ImmutableArray.Empty; + + // Gather the type hierarchy, only if the type is nested (as an optimization) + if (symbol.ContainingType is not null) + { + List hierarchyList = new(); + + for (ITypeSymbol parent = symbol; parent is not null; parent = parent.ContainingType) + { + hierarchyList.Add(new TypeInfo( + parent.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), + parent.TypeKind, + parent.IsRecord)); + } + + classHierarchy = ImmutableArray.CreateRange(hierarchyList); + } + + return new VtableAttribute( + isAuthoring ? "ABI.Impl." + @namespace : @namespace, + isGlobalNamespace, + typeName, + classHierarchy, + ToVtableLookupString(symbol), + interfacesToAddToVtable.ToImmutableArray(), + genericInterfacesToAddToVtable.ToImmutableArray(), + symbol is IArrayTypeSymbol, + isDelegate, + symbol.DeclaredAccessibility == Accessibility.Public, + GetRuntimeClassName(interfaceToUseForRuntimeClassName, isWinRTType, mapper)); + + void AddGenericInterfaceInstantiation(INamedTypeSymbol iface) + { + if (iface.IsGenericType) + { + List genericParameters = new(); + foreach (var genericParameter in iface.TypeArguments) + { + var isNullable = genericParameter.IsValueType && genericParameter.NullableAnnotation.HasFlag(NullableAnnotation.Annotated); + + // Handle initialization of nested generics as they may not be + // initialized already. + if (!isNullable && + genericParameter is INamedTypeSymbol genericParameterIface && + genericParameterIface.IsGenericType) + { + AddGenericInterfaceInstantiation(genericParameterIface); + } + + genericParameters.Add(new GenericParameter( + ToFullyQualifiedString(genericParameter), + GeneratorHelper.GetAbiType(genericParameter, mapper), + isNullable ? TypeKind.Interface : genericParameter.TypeKind)); + } + + genericInterfacesToAddToVtable.Add(new GenericInterface( + ToFullyQualifiedString(iface), + $$"""{{iface.ContainingNamespace}}.{{iface.MetadataName}}""", + genericParameters.ToImmutableArray())); + } + } + + bool IsExternalInternalInterface(INamedTypeSymbol iface) + { + return (iface.DeclaredAccessibility == Accessibility.Internal && !SymbolEqualityComparer.Default.Equals(iface.ContainingAssembly, compilation.Assembly)) || + (iface.IsGenericType && iface.TypeArguments.Any(typeArgument => IsExternalInternalInterface(typeArgument as INamedTypeSymbol))); + } + + // Determines the interface to use to represent the type when GetRuntimeClassName is called. + // Given these are non WinRT types implementing WinRT interfaces, we find the most derived + // interface to represent it so that it applies for most scenarios. + void CheckForInterfaceToUseForRuntimeClassName(INamedTypeSymbol iface) + { + if (!checkForRuntimeClasName) + { + return; + } + + if (interfaceToUseForRuntimeClassName is null || compilation.HasImplicitConversion(iface, interfaceToUseForRuntimeClassName)) + { + interfaceToUseForRuntimeClassName = iface; + } + } + } + + private static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(INamedTypeSymbol type, TypeMapper mapper, Stack typeStack, Func isWinRTType, out IList compatibleTypes) + { + compatibleTypes = null; + + // Out of all the C# interfaces which are valid WinRT interfaces and + // support covariance, they all only have one generic parameter, + // so scoping to only handle that. + if (type is not { IsGenericType: true, TypeParameters: [{ Variance: VarianceKind.Out, IsValueType: false }] }) + { + return false; + } + + var definition = type.OriginalDefinition; + if (!isWinRTType(definition, mapper)) + { + return false; + } + + if (typeStack == null) + { + typeStack = new Stack(); + } + else + { + if (typeStack.Contains(type)) + { + return false; + } + } + typeStack.Push(type); + + HashSet compatibleTypesForGeneric = new(SymbolEqualityComparer.Default); + + if (isWinRTType(type.TypeArguments[0], mapper)) + { + compatibleTypesForGeneric.Add(type.TypeArguments[0]); + } + + foreach (var iface in type.TypeArguments[0].AllInterfaces) + { + if (isWinRTType(iface, mapper)) + { + compatibleTypesForGeneric.Add(iface); + } + + if (iface.IsGenericType + && TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, mapper, typeStack, isWinRTType, out var compatibleIfaces)) + { + compatibleTypesForGeneric.UnionWith(compatibleIfaces); + } + } + + var baseType = type.TypeArguments[0].BaseType; + while (baseType != null) + { + if (isWinRTType(baseType, mapper)) + { + compatibleTypesForGeneric.Add(baseType); + } + baseType = baseType.BaseType; + } + + typeStack.Pop(); + + compatibleTypes = new List(compatibleTypesForGeneric.Count); + foreach (var compatibleType in compatibleTypesForGeneric) + { + compatibleTypes.Add(definition.Construct(compatibleType)); + } + + return true; + } + + private static void GenerateVtableAttributes( + SourceProductionContext sourceProductionContext, + (ImmutableArray vtableAttributes, (CsWinRTAotOptimizerProperties properties, string escapedAssemblyName) context) value) + { + if (!value.context.properties.IsCsWinRTAotOptimizerEnabled) + { + return; + } + + GenerateVtableAttributes(sourceProductionContext.AddSource, value.vtableAttributes, value.context.properties.IsCsWinRTComponent, value.context.escapedAssemblyName); + } + + internal static string GenerateVtableEntry(VtableEntry vtableEntry, string escapedAssemblyName) + { + StringBuilder source = new(); + + foreach (var genericInterface in vtableEntry.GenericInterfaces) + { + source.AppendLine(GenericVtableInitializerStrings.GetInstantiationInitFunction( + genericInterface.GenericDefinition, + genericInterface.GenericParameters, + escapedAssemblyName)); + } + + if (vtableEntry.IsDelegate) + { + var @interface = vtableEntry.Interfaces.First(); + source.AppendLine(); + source.AppendLine($$""" + var delegateInterface = new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry + { + IID = global::ABI.{{@interface}}.IID, + Vtable = global::ABI.{{@interface}}.AbiToProjectionVftablePtr + }; + + return global::WinRT.DelegateTypeDetails<{{@interface}}>.GetExposedInterfaces(delegateInterface); + """); + } + else if (vtableEntry.Interfaces.Any()) + { + source.AppendLine(); + source.AppendLine($$""" + return new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry[] + { + """); + + foreach (var @interface in vtableEntry.Interfaces) + { + var genericStartIdx = @interface.IndexOf('<'); + var interfaceStaticsMethod = @interface[..(genericStartIdx == -1 ? @interface.Length : genericStartIdx)] + "Methods"; + if (genericStartIdx != -1) + { + interfaceStaticsMethod += @interface[genericStartIdx..@interface.Length]; + } + + source.AppendLine($$""" + new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry + { + IID = global::ABI.{{interfaceStaticsMethod}}.IID, + Vtable = global::ABI.{{interfaceStaticsMethod}}.AbiToProjectionVftablePtr + }, + """); + } + source.AppendLine($$""" + }; + """); + } + else + { + source.AppendLine($$""" + return global::System.Array.Empty(); + """); + } + + return source.ToString(); + } + + internal static void GenerateVtableAttributes(Action addSource, ImmutableArray vtableAttributes, bool isCsWinRTComponentFromAotOptimizer, string escapedAssemblyName) + { + var vtableEntryToVtableClassName = new Dictionary(); + StringBuilder vtableClassesSource = new(); + bool firstVtableClass = true; + + // Using ToImmutableHashSet to avoid duplicate entries from the use of partial classes by the developer + // to split out their implementation. When they do that, we will get multiple entries here for that + // and try to generate the same attribute and file with the same data as we use the semantic model + // to get all the symbol data rather than the data at an instance of a partial class definition. + foreach (var vtableAttribute in vtableAttributes.ToImmutableHashSet()) + { + // If this is a WinRT component project and this call is coming + // from the AOT optimizer, then any public types are not handled + // right now as they are handled by the WinRT component source generator + // calling this. + if (((isCsWinRTComponentFromAotOptimizer && !vtableAttribute.IsPublic) || !isCsWinRTComponentFromAotOptimizer) && + vtableAttribute.Interfaces.Any()) + { + StringBuilder source = new(); + if (!vtableAttribute.IsGlobalNamespace) + { + source.AppendLine($$""" + namespace {{vtableAttribute.Namespace}} + { + """); + } + + // Check if this class shares the same vtable as another class. If so, reuse the same generated class for it. + VtableEntry entry = new(vtableAttribute.Interfaces, vtableAttribute.GenericInterfaces, vtableAttribute.IsDelegate); + bool vtableEntryExists = vtableEntryToVtableClassName.TryGetValue(entry, out var ccwClassName); + if (!vtableEntryExists) + { + var @namespace = vtableAttribute.IsGlobalNamespace ? "" : $"{vtableAttribute.Namespace}."; + ccwClassName = GeneratorHelper.EscapeTypeNameForIdentifier(@namespace + vtableAttribute.ClassName); + vtableEntryToVtableClassName.Add(entry, ccwClassName); + } + + var escapedClassName = GeneratorHelper.EscapeTypeNameForIdentifier(vtableAttribute.ClassName); + + // Simple case when the type is not nested + if (vtableAttribute.ClassHierarchy.IsEmpty) + { + if (!string.IsNullOrEmpty(vtableAttribute.RuntimeClassName)) + { + source.AppendLine($$"""[global::WinRT.WinRTRuntimeClassName("{{vtableAttribute.RuntimeClassName}}")]"""); + } + + source.AppendLine($$""" + [global::WinRT.WinRTExposedType(typeof(global::WinRT.{{escapedAssemblyName}}VtableClasses.{{ccwClassName}}WinRTTypeDetails))] + partial class {{vtableAttribute.ClassName}} + { + } + """); + } + else + { + ReadOnlySpan classHierarchy = vtableAttribute.ClassHierarchy.AsSpan(); + + // If the type is nested, correctly nest the type definition + for (int i = classHierarchy.Length - 1; i > 0; i--) + { + source.AppendLine($$""" + partial {{classHierarchy[i].GetTypeKeyword()}} {{classHierarchy[i].QualifiedName}} + { + """); + } + + // Define the inner-most item with the attribute + if (!string.IsNullOrEmpty(vtableAttribute.RuntimeClassName)) + { + source.AppendLine($$"""[global::WinRT.WinRTRuntimeClassName("{{vtableAttribute.RuntimeClassName}}")]"""); + } + + source.AppendLine($$""" + [global::WinRT.WinRTExposedType(typeof(global::WinRT.{{escapedAssemblyName}}VtableClasses.{{ccwClassName}}WinRTTypeDetails))] + partial {{classHierarchy[0].GetTypeKeyword()}} {{classHierarchy[0].QualifiedName}} + { + } + """); + + // Close all brackets + for (int i = classHierarchy.Length - 1; i > 0; i--) + { + source.AppendLine("}"); + } + } + + // Only generate class, if this is the first time we run into this set of vtables. + if (!vtableEntryExists) + { + if (firstVtableClass) + { + vtableClassesSource.AppendLine($$""" + namespace WinRT.{{escapedAssemblyName}}VtableClasses + { + """); + firstVtableClass = false; + } + else + { + vtableClassesSource.AppendLine(); + } + + vtableClassesSource.AppendLine($$""" + internal sealed class {{ccwClassName}}WinRTTypeDetails : global::WinRT.IWinRTExposedTypeDetails + { + public global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry[] GetExposedInterfaces() + { + """); + + if (vtableAttribute.Interfaces.Any()) + { + foreach (var genericInterface in vtableAttribute.GenericInterfaces) + { + vtableClassesSource.AppendLine(GenericVtableInitializerStrings.GetInstantiationInitFunction( + genericInterface.GenericDefinition, + genericInterface.GenericParameters, + escapedAssemblyName)); + } + + vtableClassesSource.AppendLine(); + vtableClassesSource.AppendLine($$""" + return new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry[] + { + """); + + foreach (var @interface in vtableAttribute.Interfaces) + { + var genericStartIdx = @interface.IndexOf('<'); + var interfaceStaticsMethod = @interface[..(genericStartIdx == -1 ? @interface.Length : genericStartIdx)] + "Methods"; + if (genericStartIdx != -1) + { + interfaceStaticsMethod += @interface[genericStartIdx..@interface.Length]; + } + + vtableClassesSource.AppendLine($$""" + new global::System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry + { + IID = global::ABI.{{interfaceStaticsMethod}}.IID, + Vtable = global::ABI.{{interfaceStaticsMethod}}.AbiToProjectionVftablePtr + }, + """); + } + vtableClassesSource.AppendLine($$""" + }; + """); + } + else + { + vtableClassesSource.AppendLine($$""" + return global::System.Array.Empty(); + """); + } + + vtableClassesSource.AppendLine($$""" + } + } + """); + } + + if (!vtableAttribute.IsGlobalNamespace) + { + source.AppendLine($@"}}"); + } + + string prefix = vtableAttribute.IsGlobalNamespace ? "" : $"{vtableAttribute.Namespace}."; + addSource($"{prefix}{escapedClassName}.WinRTVtable.g.cs", source.ToString()); + } + } + + if (vtableClassesSource.Length != 0) + { + vtableClassesSource.AppendLine("}"); + addSource($"WinRTCCWVtable.g.cs", vtableClassesSource.ToString()); + } + } + + private static void GenerateCCWForGenericInstantiation( + SourceProductionContext sourceProductionContext, + (((ImmutableArray vtableAttributeList, ImmutableArray lookupTableList) interfacesToGenerate, + ImmutableArray componentGeneratorList) genericInterfaces, + (CsWinRTAotOptimizerProperties properties, string escapedAssemblyName) context) value) + { + if (!value.context.properties.IsCsWinRTAotOptimizerEnabled) + { + return; + } + + HashSet genericInterfacesHashSet = new(value.genericInterfaces.interfacesToGenerate.vtableAttributeList); + if (value.context.properties.IsCsWinRTCcwLookupTableGeneratorEnabled) + { + genericInterfacesHashSet.UnionWith(value.genericInterfaces.interfacesToGenerate.lookupTableList); + } + + // Remove all the generic interfaces that are beign generated by the component generator. + foreach (var i in value.genericInterfaces.componentGeneratorList) + { + genericInterfacesHashSet.Remove(i); + } + + GenerateCCWForGenericInstantiation(sourceProductionContext.AddSource, genericInterfacesHashSet.ToImmutableArray(), value.context.escapedAssemblyName); + } + + internal static void GenerateCCWForGenericInstantiation(Action addSource, ImmutableArray genericInterfaces, string escapedAssemblyName) + { + StringBuilder source = new(); + + if (genericInterfaces.Any()) + { + source.AppendLine($$""" + using System; + using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; + + namespace WinRT.{{escapedAssemblyName}}GenericHelpers + { + """); + } + + var updatedGenericInterfaces = GenericVtableInitializerStrings.AddDependentGenericInterfaces(genericInterfaces.ToImmutableHashSet()); + foreach (var genericInterface in updatedGenericInterfaces) + { + source.AppendLine(); + source.AppendLine("// " + genericInterface.Interface); + source.AppendLine(GenericVtableInitializerStrings.GetInstantiation( + genericInterface.GenericDefinition, + genericInterface.GenericParameters)); + } + + if (genericInterfaces.Any()) + { + source.AppendLine("}"); + addSource($"WinRTGenericInstantiation.g.cs", source.ToString()); + } + } + + private static bool NeedVtableOnLookupTable(SyntaxNode node) + { + return (node is InvocationExpressionSyntax invocation && invocation.ArgumentList.Arguments.Count != 0) || + node is AssignmentExpressionSyntax || + node is VariableDeclarationSyntax || + node is PropertyDeclarationSyntax || + node is ReturnStatementSyntax || + node is CollectionExpressionSyntax; + } + + private static EquatableArray GetVtableAttributesToAddOnLookupTable( + GeneratorSyntaxContext context, + TypeMapper typeMapper, + bool isCsWinRTComponent) + { + var isWinRTType = GeneratorHelper.IsWinRTType(context.SemanticModel.Compilation, isCsWinRTComponent); + return GetVtableAttributesToAddOnLookupTable( + context, + typeMapper, + GeneratorHelper.IsManagedOnlyType(context.SemanticModel.Compilation), + isWinRTType, + GeneratorHelper.IsWinRTClassOrInterface(context.SemanticModel.Compilation, isWinRTType, typeMapper)); + } + + private static EquatableArray GetVtableAttributesToAddOnLookupTable( + GeneratorSyntaxContext context, + TypeMapper typeMapper, + Func isManagedOnlyType, + Func isWinRTType, + Func isWinRTClassOrInterface) + { + HashSet visitedTypes = new(SymbolEqualityComparer.Default); + HashSet vtableAttributes = new(); + + if (context.Node is InvocationExpressionSyntax invocation) + { + var invocationSymbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol; + if (invocationSymbol is IMethodSymbol methodSymbol && + // Filter checks for boxing and casts to ones calling CsWinRT projected functions and + // functions within same assembly. Functions within same assembly can take a boxed value + // and end up calling a projection function (i.e. ones generated by XAML compiler) + // In theory, another library can also be called which can call a projected function + // but not handling those scenarios for now. + (isWinRTClassOrInterface(methodSymbol.ContainingSymbol, true) || + SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) + { + // Get the concrete types directly from the argument rather than + // using what the method accepts, which might just be an interface, so + // that we can try to include any other WinRT interfaces implemented by + // that type on the CCW when it is marshaled. + for (int idx = 0, paramsIdx = 0; idx < invocation.ArgumentList.Arguments.Count; idx++) + { + if (methodSymbol.Parameters[paramsIdx].RefKind != RefKind.Out) + { + var argumentType = context.SemanticModel.GetTypeInfo(invocation.ArgumentList.Arguments[idx].Expression); + AddVtableAttributesForType(argumentType, methodSymbol.Parameters[paramsIdx].Type); + } + + // The method parameter can be declared as params which means + // an array of arguments can be passed for it and it is the + // last argument. + if (!methodSymbol.Parameters[paramsIdx].IsParams) + { + paramsIdx++; + } + } + } + } + else if (context.Node is AssignmentExpressionSyntax assignment) + { + var leftSymbol = context.SemanticModel.GetSymbolInfo(assignment.Left).Symbol; + if (leftSymbol is IPropertySymbol propertySymbol && + (isWinRTClassOrInterface(propertySymbol.ContainingSymbol, true) || + SymbolEqualityComparer.Default.Equals(propertySymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) + { + AddVtableAttributesForType(context.SemanticModel.GetTypeInfo(assignment.Right), propertySymbol.Type); + } + else if (leftSymbol is IFieldSymbol fieldSymbol && + // WinRT interfaces don't have fields, so we don't need to check for them. + (isWinRTClassOrInterface(fieldSymbol.ContainingSymbol, false) || + SymbolEqualityComparer.Default.Equals(fieldSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) + { + AddVtableAttributesForType(context.SemanticModel.GetTypeInfo(assignment.Right), fieldSymbol.Type); + } + } + else if (context.Node is VariableDeclarationSyntax variableDeclaration) + { + // Detect scenarios where the variable declaration is to a boxed or cast type during initialization. + var leftSymbol = context.SemanticModel.GetSymbolInfo(variableDeclaration.Type).Symbol; + if (leftSymbol is INamedTypeSymbol namedType) + { + foreach (var variable in variableDeclaration.Variables) + { + if (variable.Initializer != null) + { + var instantiatedType = context.SemanticModel.GetTypeInfo(variable.Initializer.Value); + AddVtableAttributesForType(instantiatedType, namedType); + } + } + } + } + else if (context.Node is PropertyDeclarationSyntax propertyDeclaration) + { + // Detect scenarios where the property declaration has an initializer and is to a boxed or cast type during initialization. + if (propertyDeclaration.Initializer != null) + { + var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol; + if (leftSymbol is INamedTypeSymbol namedType) + { + var instantiatedType = context.SemanticModel.GetTypeInfo(propertyDeclaration.Initializer.Value); + AddVtableAttributesForType(instantiatedType, namedType); + } + } + else if (propertyDeclaration.ExpressionBody != null) + { + var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol; + if (leftSymbol is INamedTypeSymbol namedType) + { + var instantiatedType = context.SemanticModel.GetTypeInfo(propertyDeclaration.ExpressionBody.Expression); + AddVtableAttributesForType(instantiatedType, namedType); + } + } + } + else if (context.Node is ReturnStatementSyntax { Expression: not null } returnDeclaration) + { + // Detect scenarios where the method or property being returned from is doing a box or cast of the type + // in the return statement. + var returnSymbol = context.SemanticModel.GetTypeInfo(returnDeclaration.Expression); + var parent = returnDeclaration.Ancestors().OfType().FirstOrDefault(); + if (parent is MethodDeclarationSyntax methodDeclaration) + { + var methodReturnSymbol = context.SemanticModel.GetSymbolInfo(methodDeclaration.ReturnType).Symbol; + if (methodReturnSymbol is ITypeSymbol typeSymbol) + { + AddVtableAttributesForType(returnSymbol, typeSymbol); + } + } + else if (parent is BasePropertyDeclarationSyntax propertyDeclarationSyntax) + { + var propertyTypeSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclarationSyntax.Type).Symbol; + if (propertyTypeSymbol is ITypeSymbol typeSymbol) + { + AddVtableAttributesForType(returnSymbol, typeSymbol); + } + } + } + else if (context.Node is CollectionExpressionSyntax collectionExpression) + { + // Detect collection expressions scenarios targeting interfaces, where we can rely on the concrete type + if (context.SemanticModel.GetOperation(collectionExpression) is ICollectionExpressionOperation operation && + operation.Type is INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true, IsUnboundGenericType: false, ConstructedFrom: not null } collectionType) + { + // Case 1: empty collection expression targeting 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList'. + // In this case, we can rely on Roslyn using an empty array. So let's pretend we saw it, and gather it for lookups. + if (operation.Elements.IsEmpty && + collectionType.ConstructedFrom.SpecialType is + SpecialType.System_Collections_Generic_IEnumerable_T or + SpecialType.System_Collections_Generic_IReadOnlyCollection_T or + SpecialType.System_Collections_Generic_IReadOnlyList_T) + { + IArrayTypeSymbol arrayTypeSymbol = context.SemanticModel.Compilation.CreateArrayTypeSymbol(collectionType.TypeArguments[0], rank: 1); + + AddVtableAttributesForTypeDirect(arrayTypeSymbol, null, collectionType); + } + else if (collectionType.ConstructedFrom.SpecialType is SpecialType.System_Collections_Generic_ICollection_T or SpecialType.System_Collections_Generic_IList_T) + { + // Case 2: a collection expression (empty or not) targeting 'ICollection' or 'IList'. + // In this case, Roslyn guarantees that 'List' will be used, so we can gather that type. + INamedTypeSymbol listOfTSymbol = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Collections.Generic.List`1")!; + INamedTypeSymbol constructedListSymbol = listOfTSymbol.Construct(collectionType.TypeArguments[0]); + + AddVtableAttributesForTypeDirect(constructedListSymbol, null, collectionType); + } + } + } + + return vtableAttributes.ToImmutableArray(); + + // Helper to directly use 'AddVtableAttributesForTypeDirect' with 'TypeInfo' values + void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType, ITypeSymbol convertedToTypeSymbol) + { + AddVtableAttributesForTypeDirect(instantiatedType.Type, instantiatedType.ConvertedType, convertedToTypeSymbol); + } + + // This handles adding vtable information for types for which we can not directly put an attribute on them. + // This includes generic types that are boxed and and non-WinRT types for which our AOT source generator hasn't + // ran on but implements WinRT interfaces. + void AddVtableAttributesForTypeDirect(ITypeSymbol instantiatedTypeSymbol, ITypeSymbol instantiatedConvertedTypeSymbol, ITypeSymbol convertedToTypeSymbol) + { + // This handles the case where there is an WinRT array possibly being assigned + // to an object type or a list. In this case, the IList interfaces of the array + // type need to be put on the CCW. + if (instantiatedTypeSymbol is IArrayTypeSymbol arrayType) + { + if (convertedToTypeSymbol is not IArrayTypeSymbol && + // Make sure we aren't just assigning it to a value type such as ReadOnlySpan + !convertedToTypeSymbol.IsValueType) + { + if (visitedTypes.Contains(arrayType)) + { + return; + } + visitedTypes.Add(arrayType); + + var vtableAtribute = GetVtableAttributeToAdd(arrayType, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); + if (vtableAtribute != default) + { + vtableAttributes.Add(vtableAtribute); + } + + // Also add the enumerator type to the lookup table as the native caller can call it. + AddEnumeratorAdapterForType(arrayType.ElementType, typeMapper, context.SemanticModel.Compilation, isManagedOnlyType, isWinRTType, vtableAttributes); + } + } + else if (instantiatedTypeSymbol is not null || instantiatedConvertedTypeSymbol is not null) + { + // Type might be null such as for lambdas, so check converted type in that case. + instantiatedTypeSymbol ??= instantiatedConvertedTypeSymbol; + + if (visitedTypes.Contains(instantiatedTypeSymbol)) + { + return; + } + visitedTypes.Add(instantiatedTypeSymbol); + + // This handles the case where a generic delegate is passed to a parameter + // statically declared as an object and thereby we won't be able to detect + // its actual type and handle it at compile time within the generated projection. + // When it is not declared as an object parameter but rather the generic delegate + // type itself, the generated marshaler code in the function makes sure the vtable + // information is available. + if (instantiatedTypeSymbol.TypeKind == TypeKind.Delegate && + instantiatedTypeSymbol.MetadataName.Contains("`") && + isWinRTType(instantiatedTypeSymbol, typeMapper) && + convertedToTypeSymbol.SpecialType == SpecialType.System_Object) + { + var argumentClassNamedTypeSymbol = instantiatedTypeSymbol as INamedTypeSymbol; + var vtableAtribute = GetVtableAttributeToAdd(instantiatedTypeSymbol, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); + if (vtableAtribute != default) + { + vtableAttributes.Add(vtableAtribute); + } + } + + // This handles the case where the source generator wasn't able to run + // and put the WinRTExposedType attribute on the class. This can be in the + // scenario where the caller defined their own generic class and + // pass it as a parameter. With generic classes, the interface itself + // might be generic too and due to that we handle it here. + // This also handles the case where the type being passed is from a different + // library which happened to not run the AOT optimizer. So as a best effort, + // we handle it here. + if (instantiatedTypeSymbol.TypeKind == TypeKind.Class) + { + bool addClassOnLookupTable = false; + if (instantiatedTypeSymbol.MetadataName.Contains("`")) + { + addClassOnLookupTable = + !GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) && + // If the type is defined in the same assembly as what the source generator is running on, + // we let the WinRTExposedType attribute generator handle it. The only scenario the generator + // doesn't handle which we handle here is if it is a generic type implementing generic WinRT interfaces. + (!SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) || + GeneratorHelper.HasNonInstantiatedWinRTGeneric(instantiatedTypeSymbol.OriginalDefinition, typeMapper)) && + // Make sure the type we are passing is being boxed or cast to another interface. + !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol); + } + else if (!isWinRTType(instantiatedTypeSymbol, typeMapper)) + { + addClassOnLookupTable = + !GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) && + // If the type is defined in the same assembly as what the source generator is running on, + // we let the WinRTExposedType attribute generator handle it. + !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) && + // Make sure the type we are passing is being boxed or cast to another interface. + !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol); + } + + if (addClassOnLookupTable) + { + var vtableAtribute = GetVtableAttributeToAdd(instantiatedTypeSymbol, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); + if (vtableAtribute != default) + { + vtableAttributes.Add(vtableAtribute); + } + + AddVtableAdapterTypeForKnownInterface(instantiatedTypeSymbol, context.SemanticModel.Compilation, isManagedOnlyType, isWinRTType, typeMapper, vtableAttributes); + } + } + } + } + } + + private static EquatableArray GetVtableAttributesToAddOnLookupTable( + GeneratorAttributeSyntaxContext context, + TypeMapper typeMapper, + bool isCsWinRTComponent) + { + var isManagedOnlyType = GeneratorHelper.IsManagedOnlyType(context.SemanticModel.Compilation); + var isWinRTType = GeneratorHelper.IsWinRTType(context.SemanticModel.Compilation, isCsWinRTComponent); + HashSet vtableAttributes = new(); + + foreach (var attributeData in context.Attributes) + { + if (attributeData.ConstructorArguments is [{ Kind: TypedConstantKind.Type, Value : ITypeSymbol vtableType }]) + { + if (vtableType is IArrayTypeSymbol arrayType) + { + var vtableAtribute = GetVtableAttributeToAdd(arrayType, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); + if (vtableAtribute != default) + { + vtableAttributes.Add(vtableAtribute); + } + + // Also add the enumerator type to the lookup table as the native caller can call it. + AddEnumeratorAdapterForType(arrayType.ElementType, typeMapper, context.SemanticModel.Compilation, isManagedOnlyType, isWinRTType, vtableAttributes); + } + else + { + var vtableAtribute = GetVtableAttributeToAdd(vtableType, isManagedOnlyType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); + if (vtableAtribute != default) + { + vtableAttributes.Add(vtableAtribute); + } + + AddVtableAdapterTypeForKnownInterface(vtableType, context.SemanticModel.Compilation, isManagedOnlyType, isWinRTType, typeMapper, vtableAttributes); + } + } + } + + return vtableAttributes.ToImmutableArray(); + } + + // Any of the IEnumerable interfaces on the vtable can be used to get the enumerator. Given IEnumerable is + // a covariant interface, it means that we can end up getting an instance of the enumerable adapter for any one + // of those covariant interfaces and thereby need vtable lookup entries for all of them. + private static void AddEnumeratorAdapterForType( + ITypeSymbol type, + TypeMapper mapper, + Compilation compilation, + Func isManagedOnlyType, + Func isWinRTType, + HashSet vtableAttributes) + { + var enumerableType = compilation.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1"); + if (enumerableType != null) + { + var constructedEnumerableType = enumerableType.Construct(type); + if (TryGetCompatibleWindowsRuntimeTypesForVariantType(constructedEnumerableType, mapper, null, isWinRTType, out var compatibleIfaces)) + { + foreach (var compatibleIface in compatibleIfaces) + { + if (compatibleIface.MetadataName == "IEnumerable`1" && + !GeneratorHelper.IsInternalInterfaceFromReferences(compatibleIface, compilation.Assembly)) + { + var enumeratorAdapterType = compilation.GetTypeByMetadataName("ABI.System.Collections.Generic.ToAbiEnumeratorAdapter`1"); + if (enumeratorAdapterType != null) + { + var constructedEnumeratorAdapterType = enumeratorAdapterType.Construct(compatibleIface.TypeArguments[0]); + var vtableAttribute = GetVtableAttributeToAdd(constructedEnumeratorAdapterType, isManagedOnlyType, isWinRTType, mapper, compilation, false); + if (vtableAttribute != default) + { + vtableAttributes.Add(vtableAttribute); + } + } + } + } + } + } + } + + internal static void AddVtableAdapterTypeForKnownInterface( + ITypeSymbol classType, + Compilation compilation, + Func isManagedOnlyType, + Func isWinRTType, + TypeMapper mapper, + HashSet vtableAttributes) + { + // If the type is blocked for marshalling, don't generate any code for any interfaces + if (isManagedOnlyType(classType)) + { + return; + } + + foreach (var iface in classType.AllInterfaces) + { + if (iface.MetadataName == "IEnumerable`1") + { + AddEnumeratorAdapterForType(iface.TypeArguments[0], mapper, compilation, isManagedOnlyType, isWinRTType, vtableAttributes); + } + else if (iface.MetadataName == "IDictionary`2") + { + LookupAndAddVtableAttributeForGenericType("System.Collections.ObjectModel.ReadOnlyDictionary`2", iface.TypeArguments); + LookupAndAddVtableAttributeForGenericType("System.Collections.Generic.KeyValuePair`2", iface.TypeArguments); + LookupAndAddVtableAttributeForGenericType("ABI.System.Collections.Generic.ConstantSplittableMap`2", iface.TypeArguments); + } + else if (iface.MetadataName == "IList`1") + { + LookupAndAddVtableAttributeForGenericType("System.Collections.ObjectModel.ReadOnlyCollection`1", iface.TypeArguments); + } + } + + if (classType is INamedTypeSymbol namedType && IsDerivedFromOrIsObservableCollection(namedType)) + { + // ObservableCollection make use of two internal built-in types as part of its + // implementation for INotifyPropertyChanged. Handling those manually here. + var genericInterfaces = new List() { "System.Collections.IList", "System.Collections.IEnumerable" }; + var mapping = mapper.GetMappedType("System.Collections.IList").GetMapping(); + var runtimeClassName = mapping.Item1 + "." + mapping.Item2; + + // System.Collections.Specialized.ReadOnlyList + vtableAttributes.Add( + new VtableAttribute( + "System.Collections.Specialized", + false, + "ReadOnlyList", + ImmutableArray.Empty, + "System.Collections.Specialized.ReadOnlyList", + genericInterfaces.ToImmutableArray(), + ImmutableArray.Empty, + false, + false, + false, + runtimeClassName)); + + // System.Collections.Specialized.SingleItemReadOnlyList + vtableAttributes.Add( + new VtableAttribute( + "System.Collections.Specialized", + false, + "SingleItemReadOnlyList", + ImmutableArray.Empty, + "System.Collections.Specialized.SingleItemReadOnlyList", + genericInterfaces.ToImmutableArray(), + ImmutableArray.Empty, + false, + false, + false, + runtimeClassName)); + } + + void LookupAndAddVtableAttributeForGenericType(string type, ImmutableArray genericArgs) + { + var genericType = compilation.GetTypeByMetadataName(type); + if (genericType != default) + { + var constructedGenericType = genericType.Construct([.. genericArgs]); + var vtableAttribute = GetVtableAttributeToAdd(constructedGenericType, isManagedOnlyType, isWinRTType, mapper, compilation, false); + if (vtableAttribute != default) + { + vtableAttributes.Add(vtableAttribute); + } + } + } + + bool IsDerivedFromOrIsObservableCollection(INamedTypeSymbol namedType) + { + return namedType.MetadataName == "ObservableCollection`1" || + (namedType.BaseType is not null && IsDerivedFromOrIsObservableCollection(namedType.BaseType)); + } + } + + private static void GenerateVtableLookupTable( + SourceProductionContext sourceProductionContext, + (ImmutableArray vtableAttributes, (CsWinRTAotOptimizerProperties properties, string)) value) + { + GenerateVtableLookupTable(sourceProductionContext.AddSource, value); + } + + internal static void GenerateVtableLookupTable( + Action addSource, + (ImmutableArray vtableAttributes, (CsWinRTAotOptimizerProperties properties, string escapedAssemblyName) context) value, + bool isComponentGenerator = false) + { + if (!value.context.properties.IsCsWinRTAotOptimizerEnabled || !value.context.properties.IsCsWinRTCcwLookupTableGeneratorEnabled) + { + return; + } + + StringBuilder source = new(); + string classPrefix = isComponentGenerator ? "Authoring" : ""; + + // The generated lookup table is based on lookup by string rather than type to avoid 2 different issues: + // + // 1) We can run into nested private types in generics which we can't reference from here but still need to be able to create the vtable for. + // 2) While looking for a type in the lookup table, you can trigger module initializers for other modules + // referenced and that can run into issues because they can have their own lookup tables that + // get registered in their module initializer, but will fail to due to the reader writer lock we have around it + // (i.e. we are traversing the lookup tables here while one is being registered). + // + // Note: just like with the authoring metadata function, we don't use a method group expression but rather construct a 'Func' ourselves. + // This is done to opt-out of the implicit caching that Roslyn does. We don't need that extra code and overhead, as this is only done once. + var hasRuntimeClasNameEntries = value.vtableAttributes.Any(static v => !string.IsNullOrEmpty(v.RuntimeClassName)); + if (value.vtableAttributes.Any()) + { + source.AppendLine($$""" + using System; + using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; + + namespace WinRT.{{value.context.escapedAssemblyName}}GenericHelpers + { + + internal static class {{classPrefix}}GlobalVtableLookup + { + + [System.Runtime.CompilerServices.ModuleInitializer] + internal static void InitializeGlobalVtableLookup() + { + ComWrappersSupport.RegisterTypeComInterfaceEntriesLookup(new Func(LookupVtableEntries)); + {{(hasRuntimeClasNameEntries ? "ComWrappersSupport.RegisterTypeRuntimeClassNameLookup(new Func(LookupRuntimeClassName));" : "")}} + } + + private static ComWrappers.ComInterfaceEntry[] LookupVtableEntries(Type type) + { + string typeName = type.ToString(); + """); + } + + // We gather all the class names that have the same vtable and generate it + // as part of one if to reduce generated code. + var vtableEntryToClassNameList = new Dictionary>(); + foreach (var vtableAttribute in value.vtableAttributes.ToImmutableHashSet()) + { + VtableEntry entry = new(vtableAttribute.Interfaces, vtableAttribute.GenericInterfaces, vtableAttribute.IsDelegate); + if (!vtableEntryToClassNameList.TryGetValue(entry, out var classNameList)) + { + classNameList = new List(); + vtableEntryToClassNameList.Add(entry, classNameList); + } + classNameList.Add(vtableAttribute.VtableLookupClassName); + } + + foreach (var vtableEntry in vtableEntryToClassNameList) + { + source.AppendLine($$""" + if (typeName == "{{vtableEntry.Value[0]}}" + """); + + for (var i = 1; i < vtableEntry.Value.Count; i++) + { + source.AppendLine($$""" + || typeName == "{{vtableEntry.Value[i]}}" + """); + } + + source.AppendLine($$""" + ) + { + {{GenerateVtableEntry(vtableEntry.Key, value.context.escapedAssemblyName)}} + } + """); + } + + if (value.vtableAttributes.Any()) + { + source.AppendLine($$""" + return default; + } + """); + + if (hasRuntimeClasNameEntries) + { + source.AppendLine($$""" + private static string LookupRuntimeClassName(Type type) + { + string typeName = type.ToString(); + """); + + var runtimeClassNameToClassNameList = new Dictionary>(); + foreach (var vtableAttribute in value.vtableAttributes.ToImmutableHashSet().Where(static v => !string.IsNullOrEmpty(v.RuntimeClassName))) + { + if (!runtimeClassNameToClassNameList.TryGetValue(vtableAttribute.RuntimeClassName, out var classNameList)) + { + classNameList = new List(); + runtimeClassNameToClassNameList.Add(vtableAttribute.RuntimeClassName, classNameList); + } + classNameList.Add(vtableAttribute.VtableLookupClassName); + } + + foreach (var entry in runtimeClassNameToClassNameList) + { + source.AppendLine($$""" + if (typeName == "{{entry.Value[0]}}" + """); + + for (var i = 1; i < entry.Value.Count; i++) + { + source.AppendLine($$""" + || typeName == "{{entry.Value[i]}}" + """); + } + + source.AppendLine($$""" + ) + { + return "{{entry.Key}}"; + } + """); + } + + source.AppendLine($$""" + return default; + } + """); + } + + source.AppendLine($$""" + } + } + """); + addSource($"WinRT{classPrefix}GlobalVtableLookup.g.cs", source.ToString()); + } + } + + private static void GenerateBindableCustomProperties( + SourceProductionContext sourceProductionContext, + (ImmutableArray bindableCustomProperties, CsWinRTAotOptimizerProperties properties) value) + { + if (!value.properties.IsCsWinRTAotOptimizerEnabled || value.bindableCustomProperties.Length == 0) + { + return; + } + + StringBuilder source = new(); + + foreach (var bindableCustomProperties in value.bindableCustomProperties) + { + if (!bindableCustomProperties.IsGlobalNamespace) + { + source.AppendLine($$""" + namespace {{bindableCustomProperties.Namespace}} + { + """); + } + + var escapedClassName = GeneratorHelper.EscapeTypeNameForIdentifier(bindableCustomProperties.TypeName); + + ReadOnlySpan classHierarchy = bindableCustomProperties.ClassHierarchy.AsSpan(); + // If the type is nested, correctly nest the type definition + for (int i = classHierarchy.Length - 1; i > 0; i--) + { + source.AppendLine($$""" + partial {{classHierarchy[i].GetTypeKeyword()}} {{classHierarchy[i].QualifiedName}} + { + """); + } + + string typeKeyword = TypeInfo.GetTypeKeyword(bindableCustomProperties.TypeKind, bindableCustomProperties.IsRecord); + + source.AppendLine($$""" + partial {{typeKeyword}} {{(classHierarchy.IsEmpty ? bindableCustomProperties.TypeName : classHierarchy[0].QualifiedName)}} : global::Microsoft.UI.Xaml.Data.IBindableCustomPropertyImplementation + { + global::Microsoft.UI.Xaml.Data.BindableCustomProperty global::Microsoft.UI.Xaml.Data.IBindableCustomPropertyImplementation.GetProperty(string name) + { + """); + + foreach (var property in bindableCustomProperties.Properties.Where(static p => !p.IsIndexer)) + { + var instanceAccessor = property.IsStatic ? bindableCustomProperties.QualifiedClassName : $$"""(({{bindableCustomProperties.QualifiedClassName}})instance)"""; + + source.AppendLine($$""" + if (name == "{{property.Name}}") + { + return new global::Microsoft.UI.Xaml.Data.BindableCustomProperty( + {{GetBoolAsString(property.CanRead)}}, + {{GetBoolAsString(property.CanWrite)}}, + "{{property.Name}}", + typeof({{property.Type}}), + {{ (property.CanRead ? $$"""static (instance) => {{instanceAccessor}}.{{property.Name}}""" : "null") }}, + {{ (property.CanWrite ? $$"""static (instance, value) => {{instanceAccessor}}.{{property.Name}} = ({{property.Type}})value""" : "null") }}, + null, + null); + } + """); + } + + source.AppendLine($$""" + return default; + } + + global::Microsoft.UI.Xaml.Data.BindableCustomProperty global::Microsoft.UI.Xaml.Data.IBindableCustomPropertyImplementation.GetProperty(global::System.Type indexParameterType) + { + """); + + foreach (var property in bindableCustomProperties.Properties.Where(static p => p.IsIndexer)) + { + var instanceAccessor = property.IsStatic ? bindableCustomProperties.QualifiedClassName : $$"""(({{bindableCustomProperties.QualifiedClassName}})instance)"""; + + source.AppendLine($$""" + if (indexParameterType == typeof({{property.IndexerType}})) + { + return new global::Microsoft.UI.Xaml.Data.BindableCustomProperty( + {{GetBoolAsString(property.CanRead)}}, + {{GetBoolAsString(property.CanWrite)}}, + "{{property.Name}}", + typeof({{property.Type}}), + null, + null, + {{ (property.CanRead ? $$"""static (instance, index) => {{instanceAccessor}}[({{property.IndexerType}})index]""" : "null") }}, + {{ (property.CanWrite ? $$"""static (instance, value, index) => {{instanceAccessor}}[({{property.IndexerType}})index] = ({{property.Type}})value""" : "null") }}); + } + """); + } + + source.AppendLine($$""" + return default; + } + } + """); + + // Close all brackets + for (int i = classHierarchy.Length - 1; i > 0; i--) + { + source.AppendLine("}"); + } + + if (!bindableCustomProperties.IsGlobalNamespace) + { + source.AppendLine($@"}}"); + } + + source.AppendLine(); + } + + sourceProductionContext.AddSource("WinRTCustomBindableProperties.g.cs", source.ToString()); + + static string GetBoolAsString(bool value) => value ? "true" : "false"; + } + } + + internal readonly record struct GenericParameter( + string ProjectedType, + string AbiType, + TypeKind TypeKind); + + internal readonly record struct GenericInterface( + string Interface, + string GenericDefinition, + EquatableArray GenericParameters); + + internal sealed record VtableAttribute( + string Namespace, + bool IsGlobalNamespace, + string ClassName, + EquatableArray ClassHierarchy, + string VtableLookupClassName, + EquatableArray Interfaces, + EquatableArray GenericInterfaces, + bool IsArray, + bool IsDelegate, + bool IsPublic, + string RuntimeClassName = default); + + sealed record VtableEntry( + EquatableArray Interfaces, + EquatableArray GenericInterfaces, + bool IsDelegate); + + internal readonly record struct BindableCustomProperty( + string Name, + string Type, + bool CanRead, + bool CanWrite, + bool IsIndexer, + string IndexerType, + bool IsStatic); + + internal readonly record struct BindableCustomProperties( + string Namespace, + bool IsGlobalNamespace, + string TypeName, + TypeKind TypeKind, + bool IsRecord, + EquatableArray ClassHierarchy, + string QualifiedClassName, + EquatableArray Properties); + + internal readonly record struct CsWinRTAotOptimizerProperties( + bool IsCsWinRTAotOptimizerEnabled, + bool IsCsWinRTComponent, + bool IsCsWinRTCcwLookupTableGeneratorEnabled, + bool IsCsWinRTAotOptimizerInAutoMode); + + /// + /// A model describing a type info in a type hierarchy. + /// + /// The qualified name for the type. + /// The kind of the type in the hierarchy. + /// Whether the type is a record type. + // Ported from https://github.com/Sergio0694/ComputeSharp + internal sealed record TypeInfo(string QualifiedName, TypeKind Kind, bool IsRecord) + { + /// + /// Gets the keyword for the current type kind. + /// + /// The keyword for the current type kind. + public string GetTypeKeyword() + { + return GetTypeKeyword(Kind, IsRecord); + } + + /// + /// Gets the keyword for a given kind and record option. + /// + /// The type kind. + /// Whether the type is a record. + /// The keyword for a given kind and record option. + public static string GetTypeKeyword(TypeKind kind, bool isRecord) + { + return kind switch + { + TypeKind.Struct when isRecord => "record struct", + TypeKind.Struct => "struct", + TypeKind.Interface => "interface", + TypeKind.Class when isRecord => "record", + _ => "class" + }; + } + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionAnalyzer.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionAnalyzer.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionSuppressor.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionSuppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.Designer.cs similarity index 97% rename from src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.Designer.cs index 07afc830d..4fe2fe15b 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.Designer.cs @@ -1,756 +1,756 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace WinRT.SourceGenerator { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class CsWinRTDiagnosticStrings { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal CsWinRTDiagnosticStrings() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinRT.SourceGenerator.CsWinRTDiagnosticStrings", typeof(CsWinRTDiagnosticStrings).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Array parameter marked InAttribute or OutAttribute. - /// - internal static string ArrayMarkedInOrOut_Brief { - get { - return ResourceManager.GetString("ArrayMarkedInOrOut_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method '{0}' has parameter '{1}' which is an array, and which has either a System.Runtime.InteropServices.InAttribute or a System.Runtime.InteropServices.OutAttribute.. - /// - internal static string ArrayMarkedInOrOut_Text1 { - get { - return ResourceManager.GetString("ArrayMarkedInOrOut_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In the Windows Runtime, array parameters must have either ReadOnlyArray or WriteOnlyArray.. - /// - internal static string ArrayMarkedInOrOut_Text2 { - get { - return ResourceManager.GetString("ArrayMarkedInOrOut_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Please remove these attributes or replace them with the appropriate Windows Runtime attribute if necessary.. - /// - internal static string ArrayMarkedInOrOut_Text3 { - get { - return ResourceManager.GetString("ArrayMarkedInOrOut_Text3", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Array parameter marked `out` and ReadOnlyArray. - /// - internal static string ArrayOutputParamMarkedRead_Brief { - get { - return ResourceManager.GetString("ArrayOutputParamMarkedRead_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method '{0}' has an output parameter '{1}' which is an array, but which has ReadOnlyArray attribute.. - /// - internal static string ArrayOutputParamMarkedRead_Text1 { - get { - return ResourceManager.GetString("ArrayOutputParamMarkedRead_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In the Windows Runtime, the contents of output arrays are writable. Please remove the attribute from '{1}'.. - /// - internal static string ArrayOutputParamMarkedRead_Text2 { - get { - return ResourceManager.GetString("ArrayOutputParamMarkedRead_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Array paramter marked both ReadOnlyArray and WriteOnlyArray. - /// - internal static string ArrayParamMarkedBoth_Brief { - get { - return ResourceManager.GetString("ArrayParamMarkedBoth_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method '{0}' has parameter '{1}' which is an array, and which has both ReadOnlyArray and WriteOnlyArray.. - /// - internal static string ArrayParamMarkedBoth_Text1 { - get { - return ResourceManager.GetString("ArrayParamMarkedBoth_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In the Windows Runtime, the contents array parameters must be either readable or writable, please remove one of the attributes from '{1}'.. - /// - internal static string ArrayParamMarkedBoth_Text2 { - get { - return ResourceManager.GetString("ArrayParamMarkedBoth_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Array parameter not marked ReadOnlyArray or WriteOnlyArray way. - /// - internal static string ArrayParamNotMarked_Brief { - get { - return ResourceManager.GetString("ArrayParamNotMarked_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method '{0}' has parameter '{1}' which is an array.. - /// - internal static string ArrayParamNotMarked_Text1 { - get { - return ResourceManager.GetString("ArrayParamNotMarked_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In the Windows Runtime, the contents of array parameters must be either readable or writable; please apply either ReadOnlyArray or WriteOnlyArray to '{1}'.. - /// - internal static string ArrayParamNotMarked_Text2 { - get { - return ResourceManager.GetString("ArrayParamNotMarked_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class '{0}' has attribute GeneratedBindableCustomProperty but it or a parent type isn't marked partial. Type and any parent types should be marked partial to allow source generation for trimming and AOT compatibility.. - /// - internal static string BindableCustomPropertyClassNotMarkedPartial_Text { - get { - return ResourceManager.GetString("BindableCustomPropertyClassNotMarkedPartial_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class Constructor Rule. - /// - internal static string ClassConstructorRule_Brief { - get { - return ResourceManager.GetString("ClassConstructorRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Classes cannot have multiple constructors of the same arity in the Windows Runtime, class {0} has multiple {1}-arity constructors. - /// - internal static string ClassConstructorRule_Text { - get { - return ResourceManager.GetString("ClassConstructorRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class not trimming / AOT compatible. - /// - internal static string ClassImplementsOldProjection_Brief { - get { - return ResourceManager.GetString("ClassImplementsOldProjection_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class '{0}' implements WinRT interface(s) {1} generated using an older version of CsWinRT. Update to a projection generated using CsWinRT 2.1.0 or later for trimming and AOT compatibility.. - /// - internal static string ClassImplementsOldProjection_Text { - get { - return ResourceManager.GetString("ClassImplementsOldProjection_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class is not marked partial. - /// - internal static string ClassNotMarkedPartial_Brief { - get { - return ResourceManager.GetString("ClassNotMarkedPartial_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class '{0}' implements WinRT interfaces but it or a parent type isn't marked partial. Type and any parent types should be marked partial for trimming and AOT compatibility if passed across the WinRT ABI.. - /// - internal static string ClassNotMarkedPartial_Text { - get { - return ResourceManager.GetString("ClassNotMarkedPartial_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class '{0}' was generated using an older version of CsWinRT and due to the type being defined in multiple DLLs, CsWinRT can not generate compat code to make it trimming safe. Update to a projection generated using CsWinRT 2.1.0 or later for trimming and AOT compatibility.. - /// - internal static string ClassOldProjectionMultipleInstances_Text { - get { - return ResourceManager.GetString("ClassOldProjectionMultipleInstances_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Namespace is disjoint from main (winmd) namespace. - /// - internal static string DisjointNamespaceRule_Brief { - get { - return ResourceManager.GetString("DisjointNamespaceRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to A public type has a namespace ('{1}') that shares no common prefix with other namespaces ('{0}').. - /// - internal static string DisjointNamespaceRule_Text1 { - get { - return ResourceManager.GetString("DisjointNamespaceRule_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to All types within a Windows Metadata file must exist in a sub namespace of the namespace that is implied by the file name.. - /// - internal static string DisjointNamespaceRule_Text2 { - get { - return ResourceManager.GetString("DisjointNamespaceRule_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Project does not enable unsafe blocks. - /// - internal static string EnableUnsafe_Brief { - get { - return ResourceManager.GetString("EnableUnsafe_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Type '{0}' implements generic WinRT interfaces which requires generated code using unsafe for trimming and AOT compatibility if passed across the WinRT ABI. Project needs to be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'.. - /// - internal static string EnableUnsafe_Text { - get { - return ResourceManager.GetString("EnableUnsafe_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class (or interface) is generic. - /// - internal static string GenericTypeRule_Brief { - get { - return ResourceManager.GetString("GenericTypeRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Type {0} is generic, Windows Runtime types cannot be generic. - /// - internal static string GenericTypeRule_Text { - get { - return ResourceManager.GetString("GenericTypeRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Array signature found with jagged array, which is not a valid WinRT type. - /// - internal static string JaggedArrayRule_Brief { - get { - return ResourceManager.GetString("JaggedArrayRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method {0} has a nested array of type {1} in its signature; arrays in Windows Runtime method signature cannot be nested. - /// - internal static string JaggedArrayRule_Text { - get { - return ResourceManager.GetString("JaggedArrayRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Array signature found with multi-dimensional array, which is not a valid Windows Runtime type. - /// - internal static string MultiDimensionalArrayRule_Brief { - get { - return ResourceManager.GetString("MultiDimensionalArrayRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method '{0}' has a multi-dimensional array of type '{1}' in its signature; arrays in Windows Runtime method signatures must be one dimensional. - /// - internal static string MultiDimensionalArrayRule_Text { - get { - return ResourceManager.GetString("MultiDimensionalArrayRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Only one overload should be designated default. - /// - internal static string MultipleDefaultOverloadAttribute_Brief { - get { - return ResourceManager.GetString("MultipleDefaultOverloadAttribute_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In class {2}: Multiple {0}-parameter overloads of '{1}' are decorated with Windows.Foundation.Metadata.DefaultOverloadAttribute.. - /// - internal static string MultipleDefaultOverloadAttribute_Text1 { - get { - return ResourceManager.GetString("MultipleDefaultOverloadAttribute_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The attribute may only be applied to one overload of the method.. - /// - internal static string MultipleDefaultOverloadAttribute_Text2 { - get { - return ResourceManager.GetString("MultipleDefaultOverloadAttribute_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Namespace names cannot differ only by case. - /// - internal static string NamespacesDifferByCase_Brief { - get { - return ResourceManager.GetString("NamespacesDifferByCase_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Multiple namespaces found with the name '{0}'; namespace names cannot differ only by case in the Windows Runtime. - /// - internal static string NamespacesDifferByCase_Text { - get { - return ResourceManager.GetString("NamespacesDifferByCase_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Multiple overloads seen without DefaultOverload attribute. - /// - internal static string NeedDefaultOverloadAttribute_Brief { - get { - return ResourceManager.GetString("NeedDefaultOverloadAttribute_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to In class {2}: The {0}-parameter overloads of {1} must have exactly one method specified as the default overload by decorating it with Windows.Foundation.Metadata.DefaultOverloadAttribute. - /// - internal static string NeedDefaultOverloadAttribute_Text { - get { - return ResourceManager.GetString("NeedDefaultOverloadAttribute_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Non-array parameter marked with ReadOnlyArray or WriteOnlyArray. - /// - internal static string NonArrayMarked_Brief { - get { - return ResourceManager.GetString("NonArrayMarked_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method '{0}' has parameter '{1}' which is not an array, and which has either a ReadOnlyArray attribute or a WriteOnlyArray attribute.. - /// - internal static string NonArrayMarked_Text1 { - get { - return ResourceManager.GetString("NonArrayMarked_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Windows Runtime does not support marking non-array parameters with ReadOnlyArray or WriteOnlyArray.. - /// - internal static string NonArrayMarked_Text2 { - get { - return ResourceManager.GetString("NonArrayMarked_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Parameter (not array type) marked InAttribute or OutAttribute. - /// - internal static string NonArrayMarkedInOrOut_Brief { - get { - return ResourceManager.GetString("NonArrayMarkedInOrOut_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method '{0}' has parameter '{1}' with a System.Runtime.InteropServices.InAttribute or System.Runtime.InteropServices.OutAttribute.Windows Runtime does not support marking parameters with System.Runtime.InteropServices.InAttribute or System.Runtime.InteropServices.OutAttribute.. - /// - internal static string NonArrayMarkedInOrOut_Text1 { - get { - return ResourceManager.GetString("NonArrayMarkedInOrOut_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Please consider removing System.Runtime.InteropServices.InAttribute and replace System.Runtime.InteropServices.OutAttribute with 'out' modifier instead.. - /// - internal static string NonArrayMarkedInOrOut_Text2 { - get { - return ResourceManager.GetString("NonArrayMarkedInOrOut_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Collection expression not safe for WinRT. - /// - internal static string NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Brief { - get { - return ResourceManager.GetString("NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Collection expressions targeting non mutable interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, a mutable interface type, or avoid using a collection expression in this case). - /// - internal static string NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Text { - get { - return ResourceManager.GetString("NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid Interface Inherited. - /// - internal static string NonWinRTInterface_Brief { - get { - return ResourceManager.GetString("NonWinRTInterface_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Windows Runtime component type {0} cannot implement interface {1}, as the interface is not a valid Windows Runtime interface. - /// - internal static string NonWinRTInterface_Text { - get { - return ResourceManager.GetString("NonWinRTInterface_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No public types defined. - /// - internal static string NoPublicTypesRule_Brief { - get { - return ResourceManager.GetString("NoPublicTypesRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Windows Runtime components must have at least one public type. - /// - internal static string NoPublicTypesRule_Text { - get { - return ResourceManager.GetString("NoPublicTypesRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Operator overload exposed. - /// - internal static string OperatorOverloadedRule_Brief { - get { - return ResourceManager.GetString("OperatorOverloadedRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} is an operator overload, managed types cannot expose operator overloads in the Windows Runtime. - /// - internal static string OperatorOverloadedRule_Text { - get { - return ResourceManager.GetString("OperatorOverloadedRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Parameter Named Value Rule. - /// - internal static string ParameterNamedValueRule_Brief { - get { - return ResourceManager.GetString("ParameterNamedValueRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The parameter name {1} in method {0} is the same as the return value parameter name used in the generated C#/WinRT interop; use a different parameter name. - /// - internal static string ParameterNamedValueRule_Text { - get { - return ResourceManager.GetString("ParameterNamedValueRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Property must have public getter. - /// - internal static string PrivateGetterRule_Brief { - get { - return ResourceManager.GetString("PrivateGetterRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Property '{0}' does not have a public getter method. Windows Runtime does not support setter-only properties.. - /// - internal static string PrivateGetterRule_Text { - get { - return ResourceManager.GetString("PrivateGetterRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Parameter passed by reference. - /// - internal static string RefParameterFound_Brief { - get { - return ResourceManager.GetString("RefParameterFound_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Method '{0}' has parameter '{1}' marked `ref`; reference parameters are not allowed in Windows Runtime. - /// - internal static string RefParameterFound_Text { - get { - return ResourceManager.GetString("RefParameterFound_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Const field in struct. - /// - internal static string StructHasConstFieldRule_Brief { - get { - return ResourceManager.GetString("StructHasConstFieldRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Structure {0} has const field - constants can only appear on Windows Runtime enumerations.. - /// - internal static string StructHasConstFieldRule_Text { - get { - return ResourceManager.GetString("StructHasConstFieldRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid field in struct. - /// - internal static string StructHasInvalidFieldRule_Brief { - get { - return ResourceManager.GetString("StructHasInvalidFieldRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Structure {0} has field of type {1}; {1} is not a valid Windows Runtime field type.. - /// - internal static string StructHasInvalidFieldRule_Text1 { - get { - return ResourceManager.GetString("StructHasInvalidFieldRule_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Each field in a Windows Runtime structure can only be UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum, or itself a structure.. - /// - internal static string StructHasInvalidFieldRule_Text2 { - get { - return ResourceManager.GetString("StructHasInvalidFieldRule_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Private field in struct. - /// - internal static string StructHasPrivateFieldRule_Brief { - get { - return ResourceManager.GetString("StructHasPrivateFieldRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Structure {0} has non-public field. All fields must be public for Windows Runtime structures.. - /// - internal static string StructHasPrivateFieldRule_Text { - get { - return ResourceManager.GetString("StructHasPrivateFieldRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Empty struct rule. - /// - internal static string StructWithNoFieldsRule_Brief { - get { - return ResourceManager.GetString("StructWithNoFieldsRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Structure {0} contains no public fields. Windows Runtime structures must contain at least one public field.. - /// - internal static string StructWithNoFieldsRule_Text { - get { - return ResourceManager.GetString("StructWithNoFieldsRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class incorrectly implements an interface. - /// - internal static string UnimplementedInterface_Brief { - get { - return ResourceManager.GetString("UnimplementedInterface_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class '{0}' does not correctly implement interface '{1}' because member '{2}' is missing or non-public. - /// - internal static string UnimplementedInterface_Text { - get { - return ResourceManager.GetString("UnimplementedInterface_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Class is unsealed. - /// - internal static string UnsealedClassRule_Brief { - get { - return ResourceManager.GetString("UnsealedClassRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Exporting unsealed types is not supported in CsWinRT, please mark type {0} as sealed. - /// - internal static string UnsealedClassRule_Text { - get { - return ResourceManager.GetString("UnsealedClassRule_Text", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Exposing unsupported type. - /// - internal static string UnsupportedTypeRule_Brief { - get { - return ResourceManager.GetString("UnsupportedTypeRule_Brief", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The member '{0}' has the type '{1}' in its signature.. - /// - internal static string UnsupportedTypeRule_Text1 { - get { - return ResourceManager.GetString("UnsupportedTypeRule_Text1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type '{1}' is not a valid Windows Runtime type.. - /// - internal static string UnsupportedTypeRule_Text2 { - get { - return ResourceManager.GetString("UnsupportedTypeRule_Text2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Yet, the type (or its generic parameters) implement interfaces that are valid Windows Runtime types.. - /// - internal static string UnsupportedTypeRule_Text3 { - get { - return ResourceManager.GetString("UnsupportedTypeRule_Text3", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Consider changing the type '{1} in the member signature to one of the following types from System.Collections.Generic: {2}.. - /// - internal static string UnsupportedTypeRule_Text4 { - get { - return ResourceManager.GetString("UnsupportedTypeRule_Text4", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace WinRT.SourceGenerator.Roslyn4080 { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class CsWinRTDiagnosticStrings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal CsWinRTDiagnosticStrings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinRT.SourceGenerator.Roslyn4080.CsWinRTDiagnosticStrings", typeof(CsWinRTDiagnosticStrings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Array parameter marked InAttribute or OutAttribute. + /// + internal static string ArrayMarkedInOrOut_Brief { + get { + return ResourceManager.GetString("ArrayMarkedInOrOut_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}' has parameter '{1}' which is an array, and which has either a System.Runtime.InteropServices.InAttribute or a System.Runtime.InteropServices.OutAttribute.. + /// + internal static string ArrayMarkedInOrOut_Text1 { + get { + return ResourceManager.GetString("ArrayMarkedInOrOut_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In the Windows Runtime, array parameters must have either ReadOnlyArray or WriteOnlyArray.. + /// + internal static string ArrayMarkedInOrOut_Text2 { + get { + return ResourceManager.GetString("ArrayMarkedInOrOut_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Please remove these attributes or replace them with the appropriate Windows Runtime attribute if necessary.. + /// + internal static string ArrayMarkedInOrOut_Text3 { + get { + return ResourceManager.GetString("ArrayMarkedInOrOut_Text3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array parameter marked `out` and ReadOnlyArray. + /// + internal static string ArrayOutputParamMarkedRead_Brief { + get { + return ResourceManager.GetString("ArrayOutputParamMarkedRead_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}' has an output parameter '{1}' which is an array, but which has ReadOnlyArray attribute.. + /// + internal static string ArrayOutputParamMarkedRead_Text1 { + get { + return ResourceManager.GetString("ArrayOutputParamMarkedRead_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In the Windows Runtime, the contents of output arrays are writable. Please remove the attribute from '{1}'.. + /// + internal static string ArrayOutputParamMarkedRead_Text2 { + get { + return ResourceManager.GetString("ArrayOutputParamMarkedRead_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array paramter marked both ReadOnlyArray and WriteOnlyArray. + /// + internal static string ArrayParamMarkedBoth_Brief { + get { + return ResourceManager.GetString("ArrayParamMarkedBoth_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}' has parameter '{1}' which is an array, and which has both ReadOnlyArray and WriteOnlyArray.. + /// + internal static string ArrayParamMarkedBoth_Text1 { + get { + return ResourceManager.GetString("ArrayParamMarkedBoth_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In the Windows Runtime, the contents array parameters must be either readable or writable, please remove one of the attributes from '{1}'.. + /// + internal static string ArrayParamMarkedBoth_Text2 { + get { + return ResourceManager.GetString("ArrayParamMarkedBoth_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array parameter not marked ReadOnlyArray or WriteOnlyArray way. + /// + internal static string ArrayParamNotMarked_Brief { + get { + return ResourceManager.GetString("ArrayParamNotMarked_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}' has parameter '{1}' which is an array.. + /// + internal static string ArrayParamNotMarked_Text1 { + get { + return ResourceManager.GetString("ArrayParamNotMarked_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In the Windows Runtime, the contents of array parameters must be either readable or writable; please apply either ReadOnlyArray or WriteOnlyArray to '{1}'.. + /// + internal static string ArrayParamNotMarked_Text2 { + get { + return ResourceManager.GetString("ArrayParamNotMarked_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class '{0}' has attribute GeneratedBindableCustomProperty but it or a parent type isn't marked partial. Type and any parent types should be marked partial to allow source generation for trimming and AOT compatibility.. + /// + internal static string BindableCustomPropertyClassNotMarkedPartial_Text { + get { + return ResourceManager.GetString("BindableCustomPropertyClassNotMarkedPartial_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class Constructor Rule. + /// + internal static string ClassConstructorRule_Brief { + get { + return ResourceManager.GetString("ClassConstructorRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Classes cannot have multiple constructors of the same arity in the Windows Runtime, class {0} has multiple {1}-arity constructors. + /// + internal static string ClassConstructorRule_Text { + get { + return ResourceManager.GetString("ClassConstructorRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class not trimming / AOT compatible. + /// + internal static string ClassImplementsOldProjection_Brief { + get { + return ResourceManager.GetString("ClassImplementsOldProjection_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class '{0}' implements WinRT interface(s) {1} generated using an older version of CsWinRT. Update to a projection generated using CsWinRT 2.1.0 or later for trimming and AOT compatibility.. + /// + internal static string ClassImplementsOldProjection_Text { + get { + return ResourceManager.GetString("ClassImplementsOldProjection_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class is not marked partial. + /// + internal static string ClassNotMarkedPartial_Brief { + get { + return ResourceManager.GetString("ClassNotMarkedPartial_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class '{0}' implements WinRT interfaces but it or a parent type isn't marked partial. Type and any parent types should be marked partial for trimming and AOT compatibility if passed across the WinRT ABI.. + /// + internal static string ClassNotMarkedPartial_Text { + get { + return ResourceManager.GetString("ClassNotMarkedPartial_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class '{0}' was generated using an older version of CsWinRT and due to the type being defined in multiple DLLs, CsWinRT can not generate compat code to make it trimming safe. Update to a projection generated using CsWinRT 2.1.0 or later for trimming and AOT compatibility.. + /// + internal static string ClassOldProjectionMultipleInstances_Text { + get { + return ResourceManager.GetString("ClassOldProjectionMultipleInstances_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Namespace is disjoint from main (winmd) namespace. + /// + internal static string DisjointNamespaceRule_Brief { + get { + return ResourceManager.GetString("DisjointNamespaceRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A public type has a namespace ('{1}') that shares no common prefix with other namespaces ('{0}').. + /// + internal static string DisjointNamespaceRule_Text1 { + get { + return ResourceManager.GetString("DisjointNamespaceRule_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All types within a Windows Metadata file must exist in a sub namespace of the namespace that is implied by the file name.. + /// + internal static string DisjointNamespaceRule_Text2 { + get { + return ResourceManager.GetString("DisjointNamespaceRule_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Project does not enable unsafe blocks. + /// + internal static string EnableUnsafe_Brief { + get { + return ResourceManager.GetString("EnableUnsafe_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' implements generic WinRT interfaces which requires generated code using unsafe for trimming and AOT compatibility if passed across the WinRT ABI. Project needs to be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'.. + /// + internal static string EnableUnsafe_Text { + get { + return ResourceManager.GetString("EnableUnsafe_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class (or interface) is generic. + /// + internal static string GenericTypeRule_Brief { + get { + return ResourceManager.GetString("GenericTypeRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type {0} is generic, Windows Runtime types cannot be generic. + /// + internal static string GenericTypeRule_Text { + get { + return ResourceManager.GetString("GenericTypeRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array signature found with jagged array, which is not a valid WinRT type. + /// + internal static string JaggedArrayRule_Brief { + get { + return ResourceManager.GetString("JaggedArrayRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method {0} has a nested array of type {1} in its signature; arrays in Windows Runtime method signature cannot be nested. + /// + internal static string JaggedArrayRule_Text { + get { + return ResourceManager.GetString("JaggedArrayRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array signature found with multi-dimensional array, which is not a valid Windows Runtime type. + /// + internal static string MultiDimensionalArrayRule_Brief { + get { + return ResourceManager.GetString("MultiDimensionalArrayRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}' has a multi-dimensional array of type '{1}' in its signature; arrays in Windows Runtime method signatures must be one dimensional. + /// + internal static string MultiDimensionalArrayRule_Text { + get { + return ResourceManager.GetString("MultiDimensionalArrayRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only one overload should be designated default. + /// + internal static string MultipleDefaultOverloadAttribute_Brief { + get { + return ResourceManager.GetString("MultipleDefaultOverloadAttribute_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In class {2}: Multiple {0}-parameter overloads of '{1}' are decorated with Windows.Foundation.Metadata.DefaultOverloadAttribute.. + /// + internal static string MultipleDefaultOverloadAttribute_Text1 { + get { + return ResourceManager.GetString("MultipleDefaultOverloadAttribute_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The attribute may only be applied to one overload of the method.. + /// + internal static string MultipleDefaultOverloadAttribute_Text2 { + get { + return ResourceManager.GetString("MultipleDefaultOverloadAttribute_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Namespace names cannot differ only by case. + /// + internal static string NamespacesDifferByCase_Brief { + get { + return ResourceManager.GetString("NamespacesDifferByCase_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multiple namespaces found with the name '{0}'; namespace names cannot differ only by case in the Windows Runtime. + /// + internal static string NamespacesDifferByCase_Text { + get { + return ResourceManager.GetString("NamespacesDifferByCase_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multiple overloads seen without DefaultOverload attribute. + /// + internal static string NeedDefaultOverloadAttribute_Brief { + get { + return ResourceManager.GetString("NeedDefaultOverloadAttribute_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In class {2}: The {0}-parameter overloads of {1} must have exactly one method specified as the default overload by decorating it with Windows.Foundation.Metadata.DefaultOverloadAttribute. + /// + internal static string NeedDefaultOverloadAttribute_Text { + get { + return ResourceManager.GetString("NeedDefaultOverloadAttribute_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-array parameter marked with ReadOnlyArray or WriteOnlyArray. + /// + internal static string NonArrayMarked_Brief { + get { + return ResourceManager.GetString("NonArrayMarked_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}' has parameter '{1}' which is not an array, and which has either a ReadOnlyArray attribute or a WriteOnlyArray attribute.. + /// + internal static string NonArrayMarked_Text1 { + get { + return ResourceManager.GetString("NonArrayMarked_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Windows Runtime does not support marking non-array parameters with ReadOnlyArray or WriteOnlyArray.. + /// + internal static string NonArrayMarked_Text2 { + get { + return ResourceManager.GetString("NonArrayMarked_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parameter (not array type) marked InAttribute or OutAttribute. + /// + internal static string NonArrayMarkedInOrOut_Brief { + get { + return ResourceManager.GetString("NonArrayMarkedInOrOut_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}' has parameter '{1}' with a System.Runtime.InteropServices.InAttribute or System.Runtime.InteropServices.OutAttribute.Windows Runtime does not support marking parameters with System.Runtime.InteropServices.InAttribute or System.Runtime.InteropServices.OutAttribute.. + /// + internal static string NonArrayMarkedInOrOut_Text1 { + get { + return ResourceManager.GetString("NonArrayMarkedInOrOut_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Please consider removing System.Runtime.InteropServices.InAttribute and replace System.Runtime.InteropServices.OutAttribute with 'out' modifier instead.. + /// + internal static string NonArrayMarkedInOrOut_Text2 { + get { + return ResourceManager.GetString("NonArrayMarkedInOrOut_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Collection expression not safe for WinRT. + /// + internal static string NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Brief { + get { + return ResourceManager.GetString("NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Collection expressions targeting non mutable interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, a mutable interface type, or avoid using a collection expression in this case). + /// + internal static string NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Text { + get { + return ResourceManager.GetString("NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Interface Inherited. + /// + internal static string NonWinRTInterface_Brief { + get { + return ResourceManager.GetString("NonWinRTInterface_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Windows Runtime component type {0} cannot implement interface {1}, as the interface is not a valid Windows Runtime interface. + /// + internal static string NonWinRTInterface_Text { + get { + return ResourceManager.GetString("NonWinRTInterface_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No public types defined. + /// + internal static string NoPublicTypesRule_Brief { + get { + return ResourceManager.GetString("NoPublicTypesRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Windows Runtime components must have at least one public type. + /// + internal static string NoPublicTypesRule_Text { + get { + return ResourceManager.GetString("NoPublicTypesRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Operator overload exposed. + /// + internal static string OperatorOverloadedRule_Brief { + get { + return ResourceManager.GetString("OperatorOverloadedRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is an operator overload, managed types cannot expose operator overloads in the Windows Runtime. + /// + internal static string OperatorOverloadedRule_Text { + get { + return ResourceManager.GetString("OperatorOverloadedRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parameter Named Value Rule. + /// + internal static string ParameterNamedValueRule_Brief { + get { + return ResourceManager.GetString("ParameterNamedValueRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The parameter name {1} in method {0} is the same as the return value parameter name used in the generated C#/WinRT interop; use a different parameter name. + /// + internal static string ParameterNamedValueRule_Text { + get { + return ResourceManager.GetString("ParameterNamedValueRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Property must have public getter. + /// + internal static string PrivateGetterRule_Brief { + get { + return ResourceManager.GetString("PrivateGetterRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Property '{0}' does not have a public getter method. Windows Runtime does not support setter-only properties.. + /// + internal static string PrivateGetterRule_Text { + get { + return ResourceManager.GetString("PrivateGetterRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parameter passed by reference. + /// + internal static string RefParameterFound_Brief { + get { + return ResourceManager.GetString("RefParameterFound_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}' has parameter '{1}' marked `ref`; reference parameters are not allowed in Windows Runtime. + /// + internal static string RefParameterFound_Text { + get { + return ResourceManager.GetString("RefParameterFound_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Const field in struct. + /// + internal static string StructHasConstFieldRule_Brief { + get { + return ResourceManager.GetString("StructHasConstFieldRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Structure {0} has const field - constants can only appear on Windows Runtime enumerations.. + /// + internal static string StructHasConstFieldRule_Text { + get { + return ResourceManager.GetString("StructHasConstFieldRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid field in struct. + /// + internal static string StructHasInvalidFieldRule_Brief { + get { + return ResourceManager.GetString("StructHasInvalidFieldRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Structure {0} has field of type {1}; {1} is not a valid Windows Runtime field type.. + /// + internal static string StructHasInvalidFieldRule_Text1 { + get { + return ResourceManager.GetString("StructHasInvalidFieldRule_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Each field in a Windows Runtime structure can only be UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum, or itself a structure.. + /// + internal static string StructHasInvalidFieldRule_Text2 { + get { + return ResourceManager.GetString("StructHasInvalidFieldRule_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Private field in struct. + /// + internal static string StructHasPrivateFieldRule_Brief { + get { + return ResourceManager.GetString("StructHasPrivateFieldRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Structure {0} has non-public field. All fields must be public for Windows Runtime structures.. + /// + internal static string StructHasPrivateFieldRule_Text { + get { + return ResourceManager.GetString("StructHasPrivateFieldRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Empty struct rule. + /// + internal static string StructWithNoFieldsRule_Brief { + get { + return ResourceManager.GetString("StructWithNoFieldsRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Structure {0} contains no public fields. Windows Runtime structures must contain at least one public field.. + /// + internal static string StructWithNoFieldsRule_Text { + get { + return ResourceManager.GetString("StructWithNoFieldsRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class incorrectly implements an interface. + /// + internal static string UnimplementedInterface_Brief { + get { + return ResourceManager.GetString("UnimplementedInterface_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class '{0}' does not correctly implement interface '{1}' because member '{2}' is missing or non-public. + /// + internal static string UnimplementedInterface_Text { + get { + return ResourceManager.GetString("UnimplementedInterface_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Class is unsealed. + /// + internal static string UnsealedClassRule_Brief { + get { + return ResourceManager.GetString("UnsealedClassRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exporting unsealed types is not supported in CsWinRT, please mark type {0} as sealed. + /// + internal static string UnsealedClassRule_Text { + get { + return ResourceManager.GetString("UnsealedClassRule_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exposing unsupported type. + /// + internal static string UnsupportedTypeRule_Brief { + get { + return ResourceManager.GetString("UnsupportedTypeRule_Brief", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The member '{0}' has the type '{1}' in its signature.. + /// + internal static string UnsupportedTypeRule_Text1 { + get { + return ResourceManager.GetString("UnsupportedTypeRule_Text1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type '{1}' is not a valid Windows Runtime type.. + /// + internal static string UnsupportedTypeRule_Text2 { + get { + return ResourceManager.GetString("UnsupportedTypeRule_Text2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Yet, the type (or its generic parameters) implement interfaces that are valid Windows Runtime types.. + /// + internal static string UnsupportedTypeRule_Text3 { + get { + return ResourceManager.GetString("UnsupportedTypeRule_Text3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Consider changing the type '{1} in the member signature to one of the following types from System.Collections.Generic: {2}.. + /// + internal static string UnsupportedTypeRule_Text4 { + get { + return ResourceManager.GetString("UnsupportedTypeRule_Text4", resourceCulture); + } + } + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.resx index c0fff5f05..3cba34f43 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.resx @@ -1,301 +1,301 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Array parameter marked InAttribute or OutAttribute - - - Method '{0}' has parameter '{1}' which is an array, and which has either a System.Runtime.InteropServices.InAttribute or a System.Runtime.InteropServices.OutAttribute. - - - In the Windows Runtime, array parameters must have either ReadOnlyArray or WriteOnlyArray. - - - Please remove these attributes or replace them with the appropriate Windows Runtime attribute if necessary. - - - Array parameter marked `out` and ReadOnlyArray - - - Method '{0}' has an output parameter '{1}' which is an array, but which has ReadOnlyArray attribute. - - - In the Windows Runtime, the contents of output arrays are writable. Please remove the attribute from '{1}'. - - - Array paramter marked both ReadOnlyArray and WriteOnlyArray - - - Method '{0}' has parameter '{1}' which is an array, and which has both ReadOnlyArray and WriteOnlyArray. - - - In the Windows Runtime, the contents array parameters must be either readable or writable, please remove one of the attributes from '{1}'. - - - Array parameter not marked ReadOnlyArray or WriteOnlyArray way - - - Method '{0}' has parameter '{1}' which is an array. - - - In the Windows Runtime, the contents of array parameters must be either readable or writable; please apply either ReadOnlyArray or WriteOnlyArray to '{1}'. - - - Class Constructor Rule - - - Classes cannot have multiple constructors of the same arity in the Windows Runtime, class {0} has multiple {1}-arity constructors - - - Class not trimming / AOT compatible - - - Class '{0}' implements WinRT interface(s) {1} generated using an older version of CsWinRT. Update to a projection generated using CsWinRT 2.1.0 or later for trimming and AOT compatibility. - - - Class '{0}' was generated using an older version of CsWinRT and due to the type being defined in multiple DLLs, CsWinRT can not generate compat code to make it trimming safe. Update to a projection generated using CsWinRT 2.1.0 or later for trimming and AOT compatibility. - - - Class is not marked partial - - - Class '{0}' implements WinRT interfaces but it or a parent type isn't marked partial. Type and any parent types should be marked partial for trimming and AOT compatibility if passed across the WinRT ABI. - - - Class '{0}' has attribute GeneratedBindableCustomProperty but it or a parent type isn't marked partial. Type and any parent types should be marked partial to allow source generation for trimming and AOT compatibility. - - - Namespace is disjoint from main (winmd) namespace - - - A public type has a namespace ('{1}') that shares no common prefix with other namespaces ('{0}'). - {1} and {0} will be some user-defined keyword - - - All types within a Windows Metadata file must exist in a sub namespace of the namespace that is implied by the file name. - "sub namespace" means a namespace defined within another namespace - - - Project does not enable unsafe blocks - - - Type '{0}' implements generic WinRT interfaces which requires generated code using unsafe for trimming and AOT compatibility if passed across the WinRT ABI. Project needs to be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. - - - Class (or interface) is generic - - - Type {0} is generic, Windows Runtime types cannot be generic - {0} will be some user-defined keyword - - - Array signature found with jagged array, which is not a valid WinRT type - - - Method {0} has a nested array of type {1} in its signature; arrays in Windows Runtime method signature cannot be nested - - - Array signature found with multi-dimensional array, which is not a valid Windows Runtime type - - - Method '{0}' has a multi-dimensional array of type '{1}' in its signature; arrays in Windows Runtime method signatures must be one dimensional - - - Only one overload should be designated default - - - In class {2}: Multiple {0}-parameter overloads of '{1}' are decorated with Windows.Foundation.Metadata.DefaultOverloadAttribute. - - - The attribute may only be applied to one overload of the method. - - - Namespace names cannot differ only by case - - - Multiple namespaces found with the name '{0}'; namespace names cannot differ only by case in the Windows Runtime - {0} will be some user-defined keyword - - - Multiple overloads seen without DefaultOverload attribute - - - In class {2}: The {0}-parameter overloads of {1} must have exactly one method specified as the default overload by decorating it with Windows.Foundation.Metadata.DefaultOverloadAttribute - - - Parameter (not array type) marked InAttribute or OutAttribute - - - Method '{0}' has parameter '{1}' with a System.Runtime.InteropServices.InAttribute or System.Runtime.InteropServices.OutAttribute.Windows Runtime does not support marking parameters with System.Runtime.InteropServices.InAttribute or System.Runtime.InteropServices.OutAttribute. - - - Please consider removing System.Runtime.InteropServices.InAttribute and replace System.Runtime.InteropServices.OutAttribute with 'out' modifier instead. - - - Non-array parameter marked with ReadOnlyArray or WriteOnlyArray - - - Method '{0}' has parameter '{1}' which is not an array, and which has either a ReadOnlyArray attribute or a WriteOnlyArray attribute. - - - Windows Runtime does not support marking non-array parameters with ReadOnlyArray or WriteOnlyArray. - - - Invalid Interface Inherited - - - Windows Runtime component type {0} cannot implement interface {1}, as the interface is not a valid Windows Runtime interface - - - No public types defined - - - Windows Runtime components must have at least one public type - - - Operator overload exposed - - - {0} is an operator overload, managed types cannot expose operator overloads in the Windows Runtime - - - Parameter Named Value Rule - - - The parameter name {1} in method {0} is the same as the return value parameter name used in the generated C#/WinRT interop; use a different parameter name - - - Property must have public getter - - - Property '{0}' does not have a public getter method. Windows Runtime does not support setter-only properties. - {0} will be some user-defined keyword - - - Parameter passed by reference - - - Method '{0}' has parameter '{1}' marked `ref`; reference parameters are not allowed in Windows Runtime - - - Const field in struct - - - Structure {0} has const field - constants can only appear on Windows Runtime enumerations. - - - Invalid field in struct - - - Structure {0} has field of type {1}; {1} is not a valid Windows Runtime field type. - - - Each field in a Windows Runtime structure can only be UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum, or itself a structure. - - - Private field in struct - - - Structure {0} has non-public field. All fields must be public for Windows Runtime structures. - - - Empty struct rule - - - Structure {0} contains no public fields. Windows Runtime structures must contain at least one public field. - - - Class incorrectly implements an interface - - - Class '{0}' does not correctly implement interface '{1}' because member '{2}' is missing or non-public - - - Class is unsealed - - - Exporting unsealed types is not supported in CsWinRT, please mark type {0} as sealed - {0} will be some user-defined keyword - - - Exposing unsupported type - - - The member '{0}' has the type '{1}' in its signature. - {0} and {1} will be user-defined keywords - - - The type '{1}' is not a valid Windows Runtime type. - {1} will be some user-defined keyword - - - Yet, the type (or its generic parameters) implement interfaces that are valid Windows Runtime types. - - - Consider changing the type '{1} in the member signature to one of the following types from System.Collections.Generic: {2}. - {1} and {2} will be keywords (types) from DotNet - - - Collection expression not safe for WinRT - - - Collection expressions targeting non mutable interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, a mutable interface type, or avoid using a collection expression in this case) - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Array parameter marked InAttribute or OutAttribute + + + Method '{0}' has parameter '{1}' which is an array, and which has either a System.Runtime.InteropServices.InAttribute or a System.Runtime.InteropServices.OutAttribute. + + + In the Windows Runtime, array parameters must have either ReadOnlyArray or WriteOnlyArray. + + + Please remove these attributes or replace them with the appropriate Windows Runtime attribute if necessary. + + + Array parameter marked `out` and ReadOnlyArray + + + Method '{0}' has an output parameter '{1}' which is an array, but which has ReadOnlyArray attribute. + + + In the Windows Runtime, the contents of output arrays are writable. Please remove the attribute from '{1}'. + + + Array paramter marked both ReadOnlyArray and WriteOnlyArray + + + Method '{0}' has parameter '{1}' which is an array, and which has both ReadOnlyArray and WriteOnlyArray. + + + In the Windows Runtime, the contents array parameters must be either readable or writable, please remove one of the attributes from '{1}'. + + + Array parameter not marked ReadOnlyArray or WriteOnlyArray way + + + Method '{0}' has parameter '{1}' which is an array. + + + In the Windows Runtime, the contents of array parameters must be either readable or writable; please apply either ReadOnlyArray or WriteOnlyArray to '{1}'. + + + Class Constructor Rule + + + Classes cannot have multiple constructors of the same arity in the Windows Runtime, class {0} has multiple {1}-arity constructors + + + Class not trimming / AOT compatible + + + Class '{0}' implements WinRT interface(s) {1} generated using an older version of CsWinRT. Update to a projection generated using CsWinRT 2.1.0 or later for trimming and AOT compatibility. + + + Class '{0}' was generated using an older version of CsWinRT and due to the type being defined in multiple DLLs, CsWinRT can not generate compat code to make it trimming safe. Update to a projection generated using CsWinRT 2.1.0 or later for trimming and AOT compatibility. + + + Class is not marked partial + + + Class '{0}' implements WinRT interfaces but it or a parent type isn't marked partial. Type and any parent types should be marked partial for trimming and AOT compatibility if passed across the WinRT ABI. + + + Class '{0}' has attribute GeneratedBindableCustomProperty but it or a parent type isn't marked partial. Type and any parent types should be marked partial to allow source generation for trimming and AOT compatibility. + + + Namespace is disjoint from main (winmd) namespace + + + A public type has a namespace ('{1}') that shares no common prefix with other namespaces ('{0}'). + {1} and {0} will be some user-defined keyword + + + All types within a Windows Metadata file must exist in a sub namespace of the namespace that is implied by the file name. + "sub namespace" means a namespace defined within another namespace + + + Project does not enable unsafe blocks + + + Type '{0}' implements generic WinRT interfaces which requires generated code using unsafe for trimming and AOT compatibility if passed across the WinRT ABI. Project needs to be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. + + + Class (or interface) is generic + + + Type {0} is generic, Windows Runtime types cannot be generic + {0} will be some user-defined keyword + + + Array signature found with jagged array, which is not a valid WinRT type + + + Method {0} has a nested array of type {1} in its signature; arrays in Windows Runtime method signature cannot be nested + + + Array signature found with multi-dimensional array, which is not a valid Windows Runtime type + + + Method '{0}' has a multi-dimensional array of type '{1}' in its signature; arrays in Windows Runtime method signatures must be one dimensional + + + Only one overload should be designated default + + + In class {2}: Multiple {0}-parameter overloads of '{1}' are decorated with Windows.Foundation.Metadata.DefaultOverloadAttribute. + + + The attribute may only be applied to one overload of the method. + + + Namespace names cannot differ only by case + + + Multiple namespaces found with the name '{0}'; namespace names cannot differ only by case in the Windows Runtime + {0} will be some user-defined keyword + + + Multiple overloads seen without DefaultOverload attribute + + + In class {2}: The {0}-parameter overloads of {1} must have exactly one method specified as the default overload by decorating it with Windows.Foundation.Metadata.DefaultOverloadAttribute + + + Parameter (not array type) marked InAttribute or OutAttribute + + + Method '{0}' has parameter '{1}' with a System.Runtime.InteropServices.InAttribute or System.Runtime.InteropServices.OutAttribute.Windows Runtime does not support marking parameters with System.Runtime.InteropServices.InAttribute or System.Runtime.InteropServices.OutAttribute. + + + Please consider removing System.Runtime.InteropServices.InAttribute and replace System.Runtime.InteropServices.OutAttribute with 'out' modifier instead. + + + Non-array parameter marked with ReadOnlyArray or WriteOnlyArray + + + Method '{0}' has parameter '{1}' which is not an array, and which has either a ReadOnlyArray attribute or a WriteOnlyArray attribute. + + + Windows Runtime does not support marking non-array parameters with ReadOnlyArray or WriteOnlyArray. + + + Invalid Interface Inherited + + + Windows Runtime component type {0} cannot implement interface {1}, as the interface is not a valid Windows Runtime interface + + + No public types defined + + + Windows Runtime components must have at least one public type + + + Operator overload exposed + + + {0} is an operator overload, managed types cannot expose operator overloads in the Windows Runtime + + + Parameter Named Value Rule + + + The parameter name {1} in method {0} is the same as the return value parameter name used in the generated C#/WinRT interop; use a different parameter name + + + Property must have public getter + + + Property '{0}' does not have a public getter method. Windows Runtime does not support setter-only properties. + {0} will be some user-defined keyword + + + Parameter passed by reference + + + Method '{0}' has parameter '{1}' marked `ref`; reference parameters are not allowed in Windows Runtime + + + Const field in struct + + + Structure {0} has const field - constants can only appear on Windows Runtime enumerations. + + + Invalid field in struct + + + Structure {0} has field of type {1}; {1} is not a valid Windows Runtime field type. + + + Each field in a Windows Runtime structure can only be UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum, or itself a structure. + + + Private field in struct + + + Structure {0} has non-public field. All fields must be public for Windows Runtime structures. + + + Empty struct rule + + + Structure {0} contains no public fields. Windows Runtime structures must contain at least one public field. + + + Class incorrectly implements an interface + + + Class '{0}' does not correctly implement interface '{1}' because member '{2}' is missing or non-public + + + Class is unsealed + + + Exporting unsealed types is not supported in CsWinRT, please mark type {0} as sealed + {0} will be some user-defined keyword + + + Exposing unsupported type + + + The member '{0}' has the type '{1}' in its signature. + {0} and {1} will be user-defined keywords + + + The type '{1}' is not a valid Windows Runtime type. + {1} will be some user-defined keyword + + + Yet, the type (or its generic parameters) implement interfaces that are valid Windows Runtime types. + + + Consider changing the type '{1} in the member signature to one of the following types from System.Collections.Generic: {2}. + {1} and {2} will be keywords (types) from DotNet + + + Collection expression not safe for WinRT + + + Collection expressions targeting non mutable interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, a mutable interface type, or avoid using a collection expression in this case) + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/DiagnosticHelpers.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/DiagnosticHelpers.cs similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/DiagnosticHelpers.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/DiagnosticHelpers.cs index 8f8e55fc6..3854c93b8 100644 --- a/src/Authoring/WinRT.SourceGenerator/DiagnosticHelpers.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/DiagnosticHelpers.cs @@ -1,412 +1,412 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Runtime.CompilerServices; -using WinRT.SourceGenerator; - -namespace Generator -{ - public partial class WinRTComponentScanner - { - private void Flag() { _flag |= true; } - /// Raise the flag so we don't make a winmd, and add a diagnostic to the sourcegenerator - /// - private void Report(DiagnosticDescriptor d, Location loc, params object[] args) - { - Flag(); - _context.ReportDiagnostic(Diagnostic.Create(d, loc, args)); - } - private void ReportDiagnostic(Diagnostic d) - { - Flag(); - _context.ReportDiagnostic(d); - } - private SemanticModel GetModel(SyntaxTree t) { return _context.Compilation.GetSemanticModel(t); } - - private INamedTypeSymbol GetTypeByMetadataName(string fullyQualifiedMetadataName) - { - return _context.Compilation.GetTypeByMetadataName(fullyQualifiedMetadataName); - } - - private bool SymEq(ISymbol sym1, ISymbol sym2) { return SymbolEqualityComparer.Default.Equals(sym1, sym2); } - - /// - /// Returns true if the class represented by the symbol - /// implements any of the interfaces defined in ProhibitedAsyncInterfaces (e.g., IAsyncAction, ...) - /// The class/interface type symbolThe containing class/interface declaration - /// True iff the given class implements any of the IAsync interfaces that are not valid in Windows Runtime - private void ImplementsInvalidInterface(INamedTypeSymbol typeSymbol, TypeDeclarationSyntax typeDeclaration) - { - bool AsyncActionCase(INamedTypeSymbol sym) - { - // are we using Windows.Foundation.IAsyncAction ? - bool isWindowsFoundation = sym.ContainingNamespace.IsGlobalNamespace || - string.CompareOrdinal(sym.ContainingNamespace.Name, "Windows.Foundation") == 0; - bool isAsyncAction = string.CompareOrdinal(sym.MetadataName, "IAsyncAction") == 0; - return isWindowsFoundation && isAsyncAction; - } - - if (typeSymbol.BaseType != null && typeSymbol.BaseType.ContainingNamespace != null) - { - if (AsyncActionCase(typeSymbol.BaseType)) - { - Report(WinRTRules.NonWinRTInterface, typeDeclaration.GetLocation(), typeDeclaration.Identifier, "IAsyncAction"); - } - } - - foreach (var implementedInterface in typeSymbol.AllInterfaces) - { - if (AsyncActionCase(implementedInterface)) - { - Report(WinRTRules.NonWinRTInterface, typeDeclaration.GetLocation(), typeDeclaration.Identifier, "IAsyncAction"); - } - } - - foreach (string prohibitedInterface in nonWindowsRuntimeInterfaces) - { - if (ImplementsInterface(typeSymbol, prohibitedInterface)) - { - Report(WinRTRules.NonWinRTInterface, typeDeclaration.GetLocation(), typeDeclaration.Identifier, prohibitedInterface); - } - } - } - - /// - /// See if this class/interfaces inherits the given type - /// - /// type that might inherit - /// Inherited interface or class - private bool ImplementsInterface(INamedTypeSymbol typeSymbol, string typeToCheck) - { - if (typeSymbol == null) - { - return false; - } - - // for interface type symbols - foreach (var implementedInterface in typeSymbol.AllInterfaces) - { - if (implementedInterface.MetadataName == typeToCheck) - { - return true; - } - } - - // class type symbols might have a BaseType, like System.Exception - if (typeSymbol.BaseType != null) - { - foreach (var x in typeSymbol.BaseType.AllInterfaces) - { - if (x.MetadataName == typeToCheck) - { - return true; - } - } - var typeToCheckSymbol = GetTypeByMetadataName(typeToCheck); - if (SymEq(typeSymbol.BaseType, typeToCheckSymbol)) - { - return true; - } - // Type -> Type`n - if (typeSymbol.BaseType.MetadataName != null) - { - return typeSymbol.BaseType.MetadataName == typeToCheck; - } - } - - return false; - } - - private bool IsPublic(MemberDeclarationSyntax member) { return member.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)); } - - #region Attributes - - /// Attributes can come in one list or many, e.g. [A(),B()] vs. [A()][B()] - /// look at all possible attributes and see if any match the given string - /// attribute names need to be fully qualified, e.g. DefaultOverload is really Windows.Foundation.Metadata.DefaultOverload - /// all the syntax nodes that correspond to an attribute list - /// true iff the given attribute is in the list - private bool MatchesAnyAttribute(string attrName, SyntaxList ls) - { - foreach (var attrList in ls) - { - foreach (var attr in attrList.Attributes) - { - // no declared symbol for AttributeSyntax... - if (string.CompareOrdinal(attr.Name.ToString(), attrName) == 0) - { - return true; - } - } - } - return false; - } - - private bool MatchesAnyAttribute(string attrName, ImmutableArray attributes) - { - string attrClassName = attrName + "Attribute"; - return attributes.Any((attr) => attr.AttributeClass.Name == attrClassName); - } - - /// - /// Checks to see if an array parameter has been marked with both Write and Read attributes - /// Does extra work, by catching `ref` params, done here since this code can be used by class or interface related methods - /// Method declared - /// true if array attributes are invalid (see summary) - private void ParameterHasAttributeErrors(MethodDeclarationSyntax method) - { - // helper function, used to see if param has Ref or Out keyword - bool HasModifier(ParameterSyntax param, SyntaxKind kind) { return param.Modifiers.Where(m => m.IsKind(kind)).Any(); } - - foreach (ParameterSyntax param in method.ParameterList.Parameters) - { - var isArrayType = param.Type.IsKind(SyntaxKind.ArrayType); - bool hasReadOnlyArray = ParamHasReadOnlyAttribute(param); - bool hasWriteOnlyArray = ParamHasWriteOnlyAttribute(param); - - // Nothing can be marked `ref` - if (HasModifier(param, SyntaxKind.RefKeyword)) - { - Report(WinRTRules.RefParameterFound, method.GetLocation(), method.Identifier, param.Identifier); - } - - if (ParamHasInOrOutAttribute(param)) - { - // recommend using ReadOnlyArray or WriteOnlyArray instead of In/Out - if (isArrayType) - { - Report(WinRTRules.ArrayMarkedInOrOut, method.GetLocation(), method.Identifier, param.Identifier); - } - // if not array type, stil can't use [In] or [Out] - else - { - Report(WinRTRules.NonArrayMarkedInOrOut, method.GetLocation(), method.Identifier, param.Identifier); - } - } - - if (isArrayType) - { - bool isOutputParam = HasModifier(param, SyntaxKind.OutKeyword); - // can't be both ReadOnly and WriteOnly - if (hasReadOnlyArray && hasWriteOnlyArray) - { - Report(WinRTRules.ArrayParamMarkedBoth, method.GetLocation(), method.Identifier, param.Identifier); - } - // can't be both output (writeonly) and marked read only - else if (hasReadOnlyArray && isOutputParam) - { - Report(WinRTRules.ArrayOutputParamMarkedRead, method.GetLocation(), method.Identifier, param.Identifier); - } - // must have some indication of ReadOnly or WriteOnly - else if (!hasWriteOnlyArray && !hasReadOnlyArray && !isOutputParam) - { - Report(WinRTRules.ArrayParamNotMarked, method.GetLocation(), method.Identifier, param.Identifier); - } - } - // Non-array types shouldn't have attributes meant for arrays - else if (hasWriteOnlyArray || hasReadOnlyArray) - { - Report(WinRTRules.NonArrayMarked, method.GetLocation(), method.Identifier, param.Identifier); - } - } - } - - /// Looks at all possible attributes on a given parameter declaration - /// returns true iff any are (string) equal to the given attribute name - private bool ParamHasAttribute(ParameterSyntax param, string attrName) { return MatchesAnyAttribute(attrName, param.AttributeLists); } - - /// Check for qualified and unqualified [In] and [Out] attribute on the parameter - /// - /// True if any attribute is the In or Out attribute - private bool ParamHasInOrOutAttribute(ParameterSyntax param) { return InAndOutAttributeNames.Where(str => ParamHasAttribute(param, str)).Any(); } - private bool ParamHasReadOnlyAttribute(ParameterSyntax param) { return ReadOnlyArrayAttributeNames.Where(str => ParamHasAttribute(param, str)).Any(); } - private bool ParamHasWriteOnlyAttribute(ParameterSyntax param) { return WriteOnlyArrayAttributeNames.Where(str => ParamHasAttribute(param, str)).Any(); } - - private ISymbol GetInterfaceMemberFromClassMember(ISymbol classMember) - { - var parent = classMember.ContainingType; - foreach (var @interface in parent.AllInterfaces) - { - foreach (var interfaceMember in @interface.GetMembers()) - { - if (SymbolEqualityComparer.Default.Equals(parent.FindImplementationForInterfaceMember(interfaceMember), classMember)) - { - return interfaceMember; - } - } - } - - return null; - } - - /// Check for qualified and unqualified [DefaultOverload] attribute on the parameter< - /// - /// True if any attribute is the DefaultOverload attribute - private bool HasDefaultOverloadAttribute(MethodDeclarationSyntax method) - { - if (OverloadAttributeNames.Where(str => MatchesAnyAttribute(str, method.AttributeLists)).Any()) - { - return true; - } - - var interfaceMember = GetInterfaceMemberFromClassMember(GetModel(method.SyntaxTree).GetDeclaredSymbol(method)); - if (interfaceMember == null) - { - return false; - } - return OverloadAttributeNames.Where(str => MatchesAnyAttribute(str, interfaceMember.GetAttributes())).Any(); - } - - /// - /// Keeps track of repeated declarations of a method (overloads) and raises diagnostics according to the rule that exactly one overload should be attributed the default - /// Look for overloads of this method, checking the attributes as well attributes for - /// - /// The strings are unique names for each method -- made by its name and arity - /// Some methods may get the attribute, some may not, we keep track of this in the map. - /// - /// Once we have seen an overload and the method still has no attribute, we make a diagnostic for it - /// If we see the method again but this time with the attribute, we remove it (and its diagnostic) from the map - /// The class the method lives in -- used for creating the diagnostic - /// True iff multiple overloads of a method are found, where more than one has been designated as the default overload - private void CheckOverloadAttributes(MethodDeclarationSyntax method, - Dictionary methodHasAttributeMap, - Dictionary overloadsWithoutAttributeMap, - SyntaxToken classId) - { - int methodArity = method.ParameterList.Parameters.Count; - string methodNameWithArity = method.Identifier.Text + methodArity; - - // look at all the attributes on this method and see if any of them is the DefaultOverload attribute - bool hasDefaultOverloadAttribute = HasDefaultOverloadAttribute(method); - bool seenMethodBefore = methodHasAttributeMap.TryGetValue(methodNameWithArity, out bool methodHasAttrAlready); - - // Do we have an overload ? - if (seenMethodBefore) - { - if (hasDefaultOverloadAttribute && !methodHasAttrAlready) - { - // we've seen it, but it didnt have the attribute, so mark that it has it now - methodHasAttributeMap[methodNameWithArity] = true; - // We finally got an attribute, so dont raise a diagnostic for this method - overloadsWithoutAttributeMap.Remove(methodNameWithArity); - } - else if (hasDefaultOverloadAttribute && methodHasAttrAlready) - { - // Special case in that multiple instances of the DefaultAttribute being used on the method - Report(WinRTRules.MultipleDefaultOverloadAttribute, method.GetLocation(), methodArity, method.Identifier, classId); - } - else if (!hasDefaultOverloadAttribute && !methodHasAttrAlready) - { - // we could see this method later with the attribute, - // so hold onto the diagnostic for it until we know it doesn't have the attribute - overloadsWithoutAttributeMap[methodNameWithArity] = Diagnostic.Create( - WinRTRules.NeedDefaultOverloadAttribute, - method.GetLocation(), - methodArity, - method.Identifier, - classId); - } - } - else - { - // first time we're seeing the method, add a pair in the map for its name and whether it has the attribute - methodHasAttributeMap[methodNameWithArity] = hasDefaultOverloadAttribute; - } - } - - #endregion - - /// Make a suggestion for types to use instead of the given type - /// A type that is not valid in Windows Runtime - /// string of types that the given type implements and are valid Windows Runtime types - private string SuggestType(string type) - { - switch (type) - { - case "System.Collections.Generic.Dictionary`2": - return "IDictionary, IReadOnlyDictionary, IEnumerable>"; - case "System.Collections.ObjectModel.ReadOnlyDictionary`2": - return "IReadOnlyDictionary, IEnumerable>, IDictionary"; - case "System.Collections.Generic.List`1": - return "IList, IReadOnlyList, IEnumerable"; - case "System.Linq.Enumerable`1": - return "IEnumerable"; - case "System.Collections.Generic.KeyValuePair": - return "KeyValuePair"; - case "System.Array": - return "T[]"; - default: return "No suggestions for type"; - } - } - - /// - /// the common term for the given syntax type - private string SimplifySyntaxTypeString(string syntaxType) - { - switch (syntaxType) - { - case "EventFieldDeclarationSyntax": return "event"; - case "ConstructorDeclarationSyntax": return "constructor"; - case "DelegateDeclarationSyntax": return "delegate"; - case "IndexerDeclarationSyntax": return "indexer"; - case "MethodDeclarationSyntax": return "method"; - case "OperatorDeclarationSyntax": return "operator"; - case "PropertyDeclarationSyntax": return "property"; - default: return "unknown syntax type: " + syntaxType; - } - } - - private SpecialType[] ValidStructFieldTypes = new SpecialType[] - { - SpecialType.System_Boolean, - SpecialType.System_String, - SpecialType.System_Single, - SpecialType.System_Double, - SpecialType.System_UInt16, - SpecialType.System_UInt32, - SpecialType.System_UInt64, - SpecialType.System_Int16, - SpecialType.System_Int32, - SpecialType.System_Int64, - }; - - private static readonly HashSet nonWindowsRuntimeInterfaces = new HashSet() - { - "System.Exception", - "IAsyncActionWithProgress`1", - "IAsyncOperation`1", - "IAsyncOperationWithProgress`2", - }; - - private static readonly HashSet NotValidTypes = new HashSet() - { - "System.Array", - "System.Collections.Generic.Dictionary`2", - "System.Collections.Generic.List`1", - "System.Collections.Generic.KeyValuePair" - }; - - private static readonly HashSet WIPNotValidTypes = new HashSet() - { - "System.Linq.Enumerable", - "Enumerable", - "System.Collections.ObjectModel.ReadOnlyDictionary`2", - "ReadOnlyDictionary`2" - }; - - private static readonly HashSet InAndOutAttributeNames = new HashSet() - { "In", "Out", "System.Runtime.InteropServices.In", "System.Runtime.InteropServices.Out" }; - private static readonly HashSet OverloadAttributeNames = new HashSet() - { "DefaultOverload", "Windows.Foundation.Metadata.DefaultOverload" }; - private static readonly HashSet ReadOnlyArrayAttributeNames = new HashSet() - { "System.Runtime.InteropServices.WindowsRuntime.ReadOnlyArray", "ReadOnlyArray" }; - private static readonly HashSet WriteOnlyArrayAttributeNames = new HashSet() - { "System.Runtime.InteropServices.WindowsRuntime.WriteOnlyArray", "WriteOnlyArray" }; - - private static readonly string GeneratedReturnValueName = "__retval"; - } -} +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +using WinRT.SourceGenerator; + +namespace Generator +{ + public partial class WinRTComponentScanner + { + private void Flag() { _flag |= true; } + /// Raise the flag so we don't make a winmd, and add a diagnostic to the sourcegenerator + /// + private void Report(DiagnosticDescriptor d, Location loc, params object[] args) + { + Flag(); + _context.ReportDiagnostic(Diagnostic.Create(d, loc, args)); + } + private void ReportDiagnostic(Diagnostic d) + { + Flag(); + _context.ReportDiagnostic(d); + } + private SemanticModel GetModel(SyntaxTree t) { return _context.Compilation.GetSemanticModel(t); } + + private INamedTypeSymbol GetTypeByMetadataName(string fullyQualifiedMetadataName) + { + return _context.Compilation.GetTypeByMetadataName(fullyQualifiedMetadataName); + } + + private bool SymEq(ISymbol sym1, ISymbol sym2) { return SymbolEqualityComparer.Default.Equals(sym1, sym2); } + + /// + /// Returns true if the class represented by the symbol + /// implements any of the interfaces defined in ProhibitedAsyncInterfaces (e.g., IAsyncAction, ...) + /// The class/interface type symbolThe containing class/interface declaration + /// True iff the given class implements any of the IAsync interfaces that are not valid in Windows Runtime + private void ImplementsInvalidInterface(INamedTypeSymbol typeSymbol, TypeDeclarationSyntax typeDeclaration) + { + bool AsyncActionCase(INamedTypeSymbol sym) + { + // are we using Windows.Foundation.IAsyncAction ? + bool isWindowsFoundation = sym.ContainingNamespace.IsGlobalNamespace || + string.CompareOrdinal(sym.ContainingNamespace.Name, "Windows.Foundation") == 0; + bool isAsyncAction = string.CompareOrdinal(sym.MetadataName, "IAsyncAction") == 0; + return isWindowsFoundation && isAsyncAction; + } + + if (typeSymbol.BaseType != null && typeSymbol.BaseType.ContainingNamespace != null) + { + if (AsyncActionCase(typeSymbol.BaseType)) + { + Report(WinRTRules.NonWinRTInterface, typeDeclaration.GetLocation(), typeDeclaration.Identifier, "IAsyncAction"); + } + } + + foreach (var implementedInterface in typeSymbol.AllInterfaces) + { + if (AsyncActionCase(implementedInterface)) + { + Report(WinRTRules.NonWinRTInterface, typeDeclaration.GetLocation(), typeDeclaration.Identifier, "IAsyncAction"); + } + } + + foreach (string prohibitedInterface in nonWindowsRuntimeInterfaces) + { + if (ImplementsInterface(typeSymbol, prohibitedInterface)) + { + Report(WinRTRules.NonWinRTInterface, typeDeclaration.GetLocation(), typeDeclaration.Identifier, prohibitedInterface); + } + } + } + + /// + /// See if this class/interfaces inherits the given type + /// + /// type that might inherit + /// Inherited interface or class + private bool ImplementsInterface(INamedTypeSymbol typeSymbol, string typeToCheck) + { + if (typeSymbol == null) + { + return false; + } + + // for interface type symbols + foreach (var implementedInterface in typeSymbol.AllInterfaces) + { + if (implementedInterface.MetadataName == typeToCheck) + { + return true; + } + } + + // class type symbols might have a BaseType, like System.Exception + if (typeSymbol.BaseType != null) + { + foreach (var x in typeSymbol.BaseType.AllInterfaces) + { + if (x.MetadataName == typeToCheck) + { + return true; + } + } + var typeToCheckSymbol = GetTypeByMetadataName(typeToCheck); + if (SymEq(typeSymbol.BaseType, typeToCheckSymbol)) + { + return true; + } + // Type -> Type`n + if (typeSymbol.BaseType.MetadataName != null) + { + return typeSymbol.BaseType.MetadataName == typeToCheck; + } + } + + return false; + } + + private bool IsPublic(MemberDeclarationSyntax member) { return member.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)); } + + #region Attributes + + /// Attributes can come in one list or many, e.g. [A(),B()] vs. [A()][B()] + /// look at all possible attributes and see if any match the given string + /// attribute names need to be fully qualified, e.g. DefaultOverload is really Windows.Foundation.Metadata.DefaultOverload + /// all the syntax nodes that correspond to an attribute list + /// true iff the given attribute is in the list + private bool MatchesAnyAttribute(string attrName, SyntaxList ls) + { + foreach (var attrList in ls) + { + foreach (var attr in attrList.Attributes) + { + // no declared symbol for AttributeSyntax... + if (string.CompareOrdinal(attr.Name.ToString(), attrName) == 0) + { + return true; + } + } + } + return false; + } + + private bool MatchesAnyAttribute(string attrName, ImmutableArray attributes) + { + string attrClassName = attrName + "Attribute"; + return attributes.Any((attr) => attr.AttributeClass.Name == attrClassName); + } + + /// + /// Checks to see if an array parameter has been marked with both Write and Read attributes + /// Does extra work, by catching `ref` params, done here since this code can be used by class or interface related methods + /// Method declared + /// true if array attributes are invalid (see summary) + private void ParameterHasAttributeErrors(MethodDeclarationSyntax method) + { + // helper function, used to see if param has Ref or Out keyword + bool HasModifier(ParameterSyntax param, SyntaxKind kind) { return param.Modifiers.Where(m => m.IsKind(kind)).Any(); } + + foreach (ParameterSyntax param in method.ParameterList.Parameters) + { + var isArrayType = param.Type.IsKind(SyntaxKind.ArrayType); + bool hasReadOnlyArray = ParamHasReadOnlyAttribute(param); + bool hasWriteOnlyArray = ParamHasWriteOnlyAttribute(param); + + // Nothing can be marked `ref` + if (HasModifier(param, SyntaxKind.RefKeyword)) + { + Report(WinRTRules.RefParameterFound, method.GetLocation(), method.Identifier, param.Identifier); + } + + if (ParamHasInOrOutAttribute(param)) + { + // recommend using ReadOnlyArray or WriteOnlyArray instead of In/Out + if (isArrayType) + { + Report(WinRTRules.ArrayMarkedInOrOut, method.GetLocation(), method.Identifier, param.Identifier); + } + // if not array type, stil can't use [In] or [Out] + else + { + Report(WinRTRules.NonArrayMarkedInOrOut, method.GetLocation(), method.Identifier, param.Identifier); + } + } + + if (isArrayType) + { + bool isOutputParam = HasModifier(param, SyntaxKind.OutKeyword); + // can't be both ReadOnly and WriteOnly + if (hasReadOnlyArray && hasWriteOnlyArray) + { + Report(WinRTRules.ArrayParamMarkedBoth, method.GetLocation(), method.Identifier, param.Identifier); + } + // can't be both output (writeonly) and marked read only + else if (hasReadOnlyArray && isOutputParam) + { + Report(WinRTRules.ArrayOutputParamMarkedRead, method.GetLocation(), method.Identifier, param.Identifier); + } + // must have some indication of ReadOnly or WriteOnly + else if (!hasWriteOnlyArray && !hasReadOnlyArray && !isOutputParam) + { + Report(WinRTRules.ArrayParamNotMarked, method.GetLocation(), method.Identifier, param.Identifier); + } + } + // Non-array types shouldn't have attributes meant for arrays + else if (hasWriteOnlyArray || hasReadOnlyArray) + { + Report(WinRTRules.NonArrayMarked, method.GetLocation(), method.Identifier, param.Identifier); + } + } + } + + /// Looks at all possible attributes on a given parameter declaration + /// returns true iff any are (string) equal to the given attribute name + private bool ParamHasAttribute(ParameterSyntax param, string attrName) { return MatchesAnyAttribute(attrName, param.AttributeLists); } + + /// Check for qualified and unqualified [In] and [Out] attribute on the parameter + /// + /// True if any attribute is the In or Out attribute + private bool ParamHasInOrOutAttribute(ParameterSyntax param) { return InAndOutAttributeNames.Where(str => ParamHasAttribute(param, str)).Any(); } + private bool ParamHasReadOnlyAttribute(ParameterSyntax param) { return ReadOnlyArrayAttributeNames.Where(str => ParamHasAttribute(param, str)).Any(); } + private bool ParamHasWriteOnlyAttribute(ParameterSyntax param) { return WriteOnlyArrayAttributeNames.Where(str => ParamHasAttribute(param, str)).Any(); } + + private ISymbol GetInterfaceMemberFromClassMember(ISymbol classMember) + { + var parent = classMember.ContainingType; + foreach (var @interface in parent.AllInterfaces) + { + foreach (var interfaceMember in @interface.GetMembers()) + { + if (SymbolEqualityComparer.Default.Equals(parent.FindImplementationForInterfaceMember(interfaceMember), classMember)) + { + return interfaceMember; + } + } + } + + return null; + } + + /// Check for qualified and unqualified [DefaultOverload] attribute on the parameter< + /// + /// True if any attribute is the DefaultOverload attribute + private bool HasDefaultOverloadAttribute(MethodDeclarationSyntax method) + { + if (OverloadAttributeNames.Where(str => MatchesAnyAttribute(str, method.AttributeLists)).Any()) + { + return true; + } + + var interfaceMember = GetInterfaceMemberFromClassMember(GetModel(method.SyntaxTree).GetDeclaredSymbol(method)); + if (interfaceMember == null) + { + return false; + } + return OverloadAttributeNames.Where(str => MatchesAnyAttribute(str, interfaceMember.GetAttributes())).Any(); + } + + /// + /// Keeps track of repeated declarations of a method (overloads) and raises diagnostics according to the rule that exactly one overload should be attributed the default + /// Look for overloads of this method, checking the attributes as well attributes for + /// + /// The strings are unique names for each method -- made by its name and arity + /// Some methods may get the attribute, some may not, we keep track of this in the map. + /// + /// Once we have seen an overload and the method still has no attribute, we make a diagnostic for it + /// If we see the method again but this time with the attribute, we remove it (and its diagnostic) from the map + /// The class the method lives in -- used for creating the diagnostic + /// True iff multiple overloads of a method are found, where more than one has been designated as the default overload + private void CheckOverloadAttributes(MethodDeclarationSyntax method, + Dictionary methodHasAttributeMap, + Dictionary overloadsWithoutAttributeMap, + SyntaxToken classId) + { + int methodArity = method.ParameterList.Parameters.Count; + string methodNameWithArity = method.Identifier.Text + methodArity; + + // look at all the attributes on this method and see if any of them is the DefaultOverload attribute + bool hasDefaultOverloadAttribute = HasDefaultOverloadAttribute(method); + bool seenMethodBefore = methodHasAttributeMap.TryGetValue(methodNameWithArity, out bool methodHasAttrAlready); + + // Do we have an overload ? + if (seenMethodBefore) + { + if (hasDefaultOverloadAttribute && !methodHasAttrAlready) + { + // we've seen it, but it didnt have the attribute, so mark that it has it now + methodHasAttributeMap[methodNameWithArity] = true; + // We finally got an attribute, so dont raise a diagnostic for this method + overloadsWithoutAttributeMap.Remove(methodNameWithArity); + } + else if (hasDefaultOverloadAttribute && methodHasAttrAlready) + { + // Special case in that multiple instances of the DefaultAttribute being used on the method + Report(WinRTRules.MultipleDefaultOverloadAttribute, method.GetLocation(), methodArity, method.Identifier, classId); + } + else if (!hasDefaultOverloadAttribute && !methodHasAttrAlready) + { + // we could see this method later with the attribute, + // so hold onto the diagnostic for it until we know it doesn't have the attribute + overloadsWithoutAttributeMap[methodNameWithArity] = Diagnostic.Create( + WinRTRules.NeedDefaultOverloadAttribute, + method.GetLocation(), + methodArity, + method.Identifier, + classId); + } + } + else + { + // first time we're seeing the method, add a pair in the map for its name and whether it has the attribute + methodHasAttributeMap[methodNameWithArity] = hasDefaultOverloadAttribute; + } + } + + #endregion + + /// Make a suggestion for types to use instead of the given type + /// A type that is not valid in Windows Runtime + /// string of types that the given type implements and are valid Windows Runtime types + private string SuggestType(string type) + { + switch (type) + { + case "System.Collections.Generic.Dictionary`2": + return "IDictionary, IReadOnlyDictionary, IEnumerable>"; + case "System.Collections.ObjectModel.ReadOnlyDictionary`2": + return "IReadOnlyDictionary, IEnumerable>, IDictionary"; + case "System.Collections.Generic.List`1": + return "IList, IReadOnlyList, IEnumerable"; + case "System.Linq.Enumerable`1": + return "IEnumerable"; + case "System.Collections.Generic.KeyValuePair": + return "KeyValuePair"; + case "System.Array": + return "T[]"; + default: return "No suggestions for type"; + } + } + + /// + /// the common term for the given syntax type + private string SimplifySyntaxTypeString(string syntaxType) + { + switch (syntaxType) + { + case "EventFieldDeclarationSyntax": return "event"; + case "ConstructorDeclarationSyntax": return "constructor"; + case "DelegateDeclarationSyntax": return "delegate"; + case "IndexerDeclarationSyntax": return "indexer"; + case "MethodDeclarationSyntax": return "method"; + case "OperatorDeclarationSyntax": return "operator"; + case "PropertyDeclarationSyntax": return "property"; + default: return "unknown syntax type: " + syntaxType; + } + } + + private SpecialType[] ValidStructFieldTypes = new SpecialType[] + { + SpecialType.System_Boolean, + SpecialType.System_String, + SpecialType.System_Single, + SpecialType.System_Double, + SpecialType.System_UInt16, + SpecialType.System_UInt32, + SpecialType.System_UInt64, + SpecialType.System_Int16, + SpecialType.System_Int32, + SpecialType.System_Int64, + }; + + private static readonly HashSet nonWindowsRuntimeInterfaces = new HashSet() + { + "System.Exception", + "IAsyncActionWithProgress`1", + "IAsyncOperation`1", + "IAsyncOperationWithProgress`2", + }; + + private static readonly HashSet NotValidTypes = new HashSet() + { + "System.Array", + "System.Collections.Generic.Dictionary`2", + "System.Collections.Generic.List`1", + "System.Collections.Generic.KeyValuePair" + }; + + private static readonly HashSet WIPNotValidTypes = new HashSet() + { + "System.Linq.Enumerable", + "Enumerable", + "System.Collections.ObjectModel.ReadOnlyDictionary`2", + "ReadOnlyDictionary`2" + }; + + private static readonly HashSet InAndOutAttributeNames = new HashSet() + { "In", "Out", "System.Runtime.InteropServices.In", "System.Runtime.InteropServices.Out" }; + private static readonly HashSet OverloadAttributeNames = new HashSet() + { "DefaultOverload", "Windows.Foundation.Metadata.DefaultOverload" }; + private static readonly HashSet ReadOnlyArrayAttributeNames = new HashSet() + { "System.Runtime.InteropServices.WindowsRuntime.ReadOnlyArray", "ReadOnlyArray" }; + private static readonly HashSet WriteOnlyArrayAttributeNames = new HashSet() + { "System.Runtime.InteropServices.WindowsRuntime.WriteOnlyArray", "WriteOnlyArray" }; + + private static readonly string GeneratedReturnValueName = "__retval"; + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/DiagnosticUtils.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/DiagnosticUtils.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/DiagnosticUtils.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/DiagnosticUtils.cs diff --git a/src/Authoring/WinRT.SourceGenerator/Extensions/SymbolExtensions.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Extensions/SymbolExtensions.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/Extensions/SymbolExtensions.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/Extensions/SymbolExtensions.cs diff --git a/src/Authoring/WinRT.SourceGenerator/Generator.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Generator.cs similarity index 97% rename from src/Authoring/WinRT.SourceGenerator/Generator.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/Generator.cs index c2e159f77..64e1621b6 100644 --- a/src/Authoring/WinRT.SourceGenerator/Generator.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Generator.cs @@ -1,499 +1,499 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Reflection.PortableExecutable; -using System.Text; -using System.Threading; - -namespace Generator -{ - public class ComponentGenerator - { - private Logger Logger { get; } - private readonly GeneratorExecutionContext context; - private string tempFolder; - private readonly TypeMapper mapper; - - public ComponentGenerator(GeneratorExecutionContext context) - { - this.context = context; - Logger = new Logger(context); - mapper = new(context.AnalyzerConfigOptions.GetCsWinRTUseWindowsUIXamlProjections()); - // TODO-WuxMux: output a module initializer that validates the MUX/WUX projection mode to ensure that things don't get out of sync. - } - - [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "We need to do file IO to invoke the 'cswinrt' tool.")] - private string GetTempFolder(bool clearSourceFilesFromFolder = false) - { - if (string.IsNullOrEmpty(tempFolder) || !File.Exists(tempFolder)) - { - string outputDir = Path.Combine(Path.GetTempPath(), "CsWinRT", Path.GetRandomFileName()).TrimEnd('\\'); - Directory.CreateDirectory(outputDir); - tempFolder = outputDir; - Logger.Log("Created temp folder: " + tempFolder); - } - - if (clearSourceFilesFromFolder) - { - foreach (var file in Directory.GetFiles(tempFolder, "*.cs", SearchOption.TopDirectoryOnly)) - { - Logger.Log("Clearing " + file); - File.Delete(file); - } - } - - return tempFolder; - } - - [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "We need to do file IO to invoke the 'cswinrt' tool.")] - private void GenerateSources() - { - string cswinrtExe = context.GetCsWinRTExe(); - string assemblyName = context.GetAssemblyName(); - string winmdFile = context.GetWinmdOutputFile(); - string outputDir = GetTempFolder(true); - string windowsMetadata = context.GetCsWinRTWindowsMetadata(); - string winmds = context.GetCsWinRTDependentMetadata(); - string csWinRTExeTFM = context.GetCsWinRTExeTFM(); - - string arguments = string.Format( - "-component -input \"{0}\" -input {1} -include {2} -output \"{3}\" -input {4} -target {5} -verbose", - winmdFile, - windowsMetadata, - assemblyName, - outputDir, - winmds, - csWinRTExeTFM); - Logger.Log("Running " + cswinrtExe + " " + arguments); - - var processInfo = new ProcessStartInfo - { - FileName = cswinrtExe, - Arguments = arguments, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - WindowStyle = ProcessWindowStyle.Hidden, - CreateNoWindow = true - }; - - try - { - using var cswinrtProcess = Process.Start(processInfo); - Logger.Log(cswinrtProcess.StandardOutput.ReadToEnd()); - Logger.Log(cswinrtProcess.StandardError.ReadToEnd()); - cswinrtProcess.WaitForExit(); - - if (cswinrtProcess.ExitCode != 0) - { - throw new Win32Exception(cswinrtProcess.ExitCode); - } - - foreach (var file in Directory.GetFiles(outputDir, "*.cs", SearchOption.TopDirectoryOnly)) - { - Logger.Log("Adding " + file); - context.AddSource(Path.GetFileNameWithoutExtension(file), SourceText.From(File.ReadAllText(file), Encoding.UTF8)); - } - } - finally - { - if (!context.GetKeepGeneratedSources()) - { - Directory.Delete(outputDir, true); - } - } - } - - private void GenerateWinMD(MetadataBuilder metadataBuilder) - { - string outputFile = context.GetWinmdOutputFile(); - Logger.Log("Writing " + outputFile); - var managedPeBuilder = new ManagedPEBuilder( - new PEHeaderBuilder( - machine: Machine.I386, - imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll | Characteristics.Bit32Machine), - new MetadataRootBuilder(metadataBuilder, "WindowsRuntime 1.4"), - new BlobBuilder(), - flags: CorFlags.ILOnly); - - var peBlob = new BlobBuilder(); - managedPeBuilder.Serialize(peBlob); - - using var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write); - peBlob.WriteContentTo(fs); - } - - private bool CatchWinRTDiagnostics() - { - string assemblyName = context.GetAssemblyName(); - WinRTComponentScanner winrtScanner = new(context, assemblyName); - winrtScanner.FindDiagnostics(); - return winrtScanner.Found(); - } - - [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "This method is only setting the exit code, not doing actual file IO.")] - public void Generate() - { - if (CatchWinRTDiagnostics()) - { - Logger.Log("Exiting early -- found errors in authored runtime component."); - Logger.Close(); - Environment.ExitCode = -1; - return; - } - - try - { - string assembly = context.GetAssemblyName(); - string version = context.GetAssemblyVersion(); - MetadataBuilder metadataBuilder = new MetadataBuilder(); - - var writer = new WinRTTypeWriter( - assembly, - version, - metadataBuilder, - Logger, - mapper); - - WinRTSyntaxReceiver syntaxReceiver = (WinRTSyntaxReceiver)context.SyntaxReceiver; - Logger.Log("Found " + syntaxReceiver.Declarations.Count + " types"); - foreach (var declaration in syntaxReceiver.Declarations) - { - writer.Model = context.Compilation.GetSemanticModel(declaration.SyntaxTree); - writer.Visit(declaration); - } - writer.FinalizeGeneration(); - - GenerateWinMD(metadataBuilder); - if (!context.ShouldGenerateWinMDOnly()) - { - GenerateSources(); - writer.GenerateWinRTExposedClassAttributes(context); - } - } - catch (Exception e) - { - Logger.Log(e.ToString()); - if (e.InnerException != null) - { - Logger.Log(e.InnerException.ToString()); - } - Logger.Close(); - Environment.ExitCode = -2; - throw; - } - - Logger.Log("Done"); - Logger.Close(); - } - - private static bool ShouldEmitCallToTryGetDependentActivationFactory(GeneratorExecutionContext context) - { - if (!context.AnalyzerConfigOptions.GetCsWinRTMergeReferencedActivationFactories()) - { - return false; - } - - foreach (MetadataReference metadataReference in context.Compilation.References) - { - if (context.Compilation.GetAssemblyOrModuleSymbol(metadataReference) is not IAssemblySymbol assemblySymbol) - { - continue; - } - - // Check if the current assembly is a WinRT component (we just need one) - if (MergeReferencedActivationFactoriesGenerator.TryGetDependentAssemblyExportsTypeName( - assemblySymbol, - context.Compilation, - CancellationToken.None, - out _)) - { - return true; - } - } - - return false; - } - - /// - /// Generates the native exports for a WinRT component. - /// - /// The value to use to produce source files. - public static void GenerateWinRTNativeExports(GeneratorExecutionContext context) - { - StringBuilder builder = new(); - - builder.AppendLine(""" - // - #pragma warning disable - - namespace WinRT - { - using global::System; - using global::System.Runtime.CompilerServices; - using global::System.Runtime.InteropServices; - - /// - unsafe partial class Module - { - /// - /// Retrieves the activation factory from a DLL that contains activatable Windows Runtime classes. - /// - /// The class identifier that is associated with an activatable runtime class. - /// A pointer to the activation factory that corresponds with the class specified by . - /// The HRESULT for the operation. - /// - [UnmanagedCallersOnly(EntryPoint = nameof(DllGetActivationFactory), CallConvs = new[] { typeof(CallConvStdcall) })] - public static int DllGetActivationFactory(void* activatableClassId, void** factory) - { - const int E_INVALIDARG = unchecked((int)0x80070057); - const int CLASS_E_CLASSNOTAVAILABLE = unchecked((int)(0x80040111)); - const int S_OK = 0; - - if (activatableClassId is null || factory is null) - { - return E_INVALIDARG; - } - - try - { - scoped ReadOnlySpan fullyQualifiedTypeName = MarshalString.FromAbiUnsafe((IntPtr)activatableClassId); - - """); - - // There's three possible cases for this method: - // 1a) The project is a standalone WinRT component - // 1b) The project is a WinRT component, and we're chaining other WinRT components - // 2) The project is an app/library, but we also want to chain other WinRT components - if (context.IsCsWinRTComponent()) - { - builder.AppendLine("IntPtr obj = GetActivationFactory(fullyQualifiedTypeName);"); - builder.AppendLine(); - - // Only emit this call if we have actually generated that. We want to avoid generating - // that default implementation in every single assembly the generator runs on. - if (ShouldEmitCallToTryGetDependentActivationFactory(context)) - { - builder.AppendLine(""" - if ((void*)obj is null) - { - obj = TryGetDependentActivationFactory(fullyQualifiedTypeName); - } - - """); - } - } - else if (ShouldEmitCallToTryGetDependentActivationFactory(context)) - { - builder.AppendLine("IntPtr obj = TryGetDependentActivationFactory(fullyQualifiedTypeName);"); - builder.AppendLine(); - } - - builder.Append(""" - if ((void*)obj is null) - { - *factory = null; - - return CLASS_E_CLASSNOTAVAILABLE; - } - - *factory = (void*)obj; - - return S_OK; - } - catch (Exception e) - { - ExceptionHelpers.SetErrorInfo(e); - - return ExceptionHelpers.GetHRForException(e); - } - } - - /// - /// Determines whether the DLL that implements this function is in use. If not, the caller can unload the DLL from memory. - /// - /// This method always returns S_FALSE. - /// - [UnmanagedCallersOnly(EntryPoint = nameof(DllCanUnloadNow), CallConvs = new[] { typeof(CallConvStdcall) })] - public static int DllCanUnloadNow() - { - const int S_FALSE = 1; - - return S_FALSE; - } - } - } - """); - - context.AddSource("NativeExports.g.cs", builder.ToString()); - } - - /// - /// Generates the native exports for a WinRT component. - /// - /// The value to use to produce source files. - public static void GenerateWinRTExportsType(GeneratorExecutionContext context) - { - if (context.Compilation.AssemblyName is not { Length: > 0 } assemblyName) - { - return; - } - - // If an older CsWinRT version is referenced, it is used to generate the projection. - // The projection generated by it won't be marked partial to generate the attribute on it - // and we also don't support it with the new scenarios without updating CsWinRT package - // So skip generating them. - if (GeneratorHelper.IsOldCsWinRTExe(context)) - { - return; - } - - // Make sure to escape invalid characters for namespace names. - // See ECMA 335, II.6.2 and II.5.2/3. - if (assemblyName.AsSpan().IndexOfAny("$@`?".AsSpan()) != -1) - { - char[] buffer = new char[assemblyName.Length]; - - for (int i = 0; i < assemblyName.Length; i++) - { - buffer[i] = assemblyName[i] is '$' or '@' or '`' or '?' - ? '_' - : assemblyName[i]; - } - - assemblyName = new string(buffer); - } - - context.AddSource("ExportsType.g.cs", $$""" - // - #pragma warning disable - - [assembly: global::WinRT.WinRTAssemblyExportsType(typeof(ABI.Exports.{{assemblyName}}.Module))] - - namespace ABI.Exports.{{assemblyName}} - { - using global::System; - - /// - public static partial class Module - { - /// - public static IntPtr GetActivationFactory(ReadOnlySpan runtimeClassId) - { - return global::WinRT.Module.GetActivationFactory(runtimeClassId); - } - } - } - """); - } - } - - [Generator] - public class SourceGenerator : ISourceGenerator - { - public void Execute(GeneratorExecutionContext context) - { - if (!context.IsCsWinRTComponent() && !context.ShouldGenerateWinMDOnly()) - { - // Special case for app/library projects that also want to chain referenced WinRT components. - // This is the case for eg. a UWP app that also has some OOP background tasks. - if (context.ShouldGenerateWinRTNativeExports() && context.GetCsWinRTMergeReferencedActivationFactories()) - { - ComponentGenerator.GenerateWinRTNativeExports(context); - - return; - } - - System.Diagnostics.Debug.WriteLine($"Skipping component {context.GetAssemblyName()}"); - return; - } - - ComponentGenerator generator = new(context); - generator.Generate(); - - // Emit the native exports for NAOT compiled WinRT components, if needed - if (context.IsCsWinRTComponent() && context.ShouldGenerateWinRTNativeExports()) - { - ComponentGenerator.GenerateWinRTNativeExports(context); - } - - // Also emit the unique exported 'Module' type to avoid ambiguities in some scenarios (eg. merging) - if (context.IsCsWinRTComponent()) - { - ComponentGenerator.GenerateWinRTExportsType(context); - } - } - - public void Initialize(GeneratorInitializationContext context) - { - context.RegisterForSyntaxNotifications(() => new WinRTSyntaxReceiver()); - } - } - - class WinRTSyntaxReceiver : ISyntaxReceiver - { - public List Declarations = new(); - public List Namespaces = new(); - - private bool HasSomePublicTypes(SyntaxNode syntaxNode) - { - return syntaxNode.ChildNodes().OfType().Any(IsPublic); - } - - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) - { - // Store namespaces separately as we only need to look at them for diagnostics - // If we did store them in declarations, we would get duplicate entries in the WinMD, - // once from the namespace declaration and once from the member's declaration - if (syntaxNode is NamespaceDeclarationSyntax @namespace) - { - // We only include the namespace if it has a public type as otherwise it won't - // be projected. For partial types, there would be one instance that we encounter - // which declares the accessibility and we will use that to determine the accessibility - // of the type for the purpose of determining whether to include the namespace. - if (HasSomePublicTypes(syntaxNode)) - { - Namespaces.Add(@namespace); - } - - // Subsequent checks will fail, small performance boost to return now. - return; - } - - if (syntaxNode is not MemberDeclarationSyntax declaration || !IsPublicOrPartial(declaration)) - { - return; - } - - if (syntaxNode is ClassDeclarationSyntax || - syntaxNode is InterfaceDeclarationSyntax || - syntaxNode is EnumDeclarationSyntax || - syntaxNode is DelegateDeclarationSyntax || - syntaxNode is StructDeclarationSyntax) - { - Declarations.Add(declaration); - } - } - - private bool IsPublic(MemberDeclarationSyntax member) - { - return member.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)); - } - - private bool IsPublicOrPartial(MemberDeclarationSyntax member) - { - // We detect whether partial types are public using symbol information later. - return member.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword) || m.IsKind(SyntaxKind.PartialKeyword)); - } - } -} +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; +using System.Text; +using System.Threading; + +namespace Generator +{ + public class ComponentGenerator + { + private Logger Logger { get; } + private readonly GeneratorExecutionContext context; + private string tempFolder; + private readonly TypeMapper mapper; + + public ComponentGenerator(GeneratorExecutionContext context) + { + this.context = context; + Logger = new Logger(context); + mapper = new(context.AnalyzerConfigOptions.GetCsWinRTUseWindowsUIXamlProjections()); + // TODO-WuxMux: output a module initializer that validates the MUX/WUX projection mode to ensure that things don't get out of sync. + } + + [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "We need to do file IO to invoke the 'cswinrt' tool.")] + private string GetTempFolder(bool clearSourceFilesFromFolder = false) + { + if (string.IsNullOrEmpty(tempFolder) || !File.Exists(tempFolder)) + { + string outputDir = Path.Combine(Path.GetTempPath(), "CsWinRT", Path.GetRandomFileName()).TrimEnd('\\'); + Directory.CreateDirectory(outputDir); + tempFolder = outputDir; + Logger.Log("Created temp folder: " + tempFolder); + } + + if (clearSourceFilesFromFolder) + { + foreach (var file in Directory.GetFiles(tempFolder, "*.cs", SearchOption.TopDirectoryOnly)) + { + Logger.Log("Clearing " + file); + File.Delete(file); + } + } + + return tempFolder; + } + + [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "We need to do file IO to invoke the 'cswinrt' tool.")] + private void GenerateSources() + { + string cswinrtExe = context.GetCsWinRTExe(); + string assemblyName = context.GetAssemblyName(); + string winmdFile = context.GetWinmdOutputFile(); + string outputDir = GetTempFolder(true); + string windowsMetadata = context.GetCsWinRTWindowsMetadata(); + string winmds = context.GetCsWinRTDependentMetadata(); + string csWinRTExeTFM = context.GetCsWinRTExeTFM(); + + string arguments = string.Format( + "-component -input \"{0}\" -input {1} -include {2} -output \"{3}\" -input {4} -target {5} -verbose", + winmdFile, + windowsMetadata, + assemblyName, + outputDir, + winmds, + csWinRTExeTFM); + Logger.Log("Running " + cswinrtExe + " " + arguments); + + var processInfo = new ProcessStartInfo + { + FileName = cswinrtExe, + Arguments = arguments, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + WindowStyle = ProcessWindowStyle.Hidden, + CreateNoWindow = true + }; + + try + { + using var cswinrtProcess = Process.Start(processInfo); + Logger.Log(cswinrtProcess.StandardOutput.ReadToEnd()); + Logger.Log(cswinrtProcess.StandardError.ReadToEnd()); + cswinrtProcess.WaitForExit(); + + if (cswinrtProcess.ExitCode != 0) + { + throw new Win32Exception(cswinrtProcess.ExitCode); + } + + foreach (var file in Directory.GetFiles(outputDir, "*.cs", SearchOption.TopDirectoryOnly)) + { + Logger.Log("Adding " + file); + context.AddSource(Path.GetFileNameWithoutExtension(file), SourceText.From(File.ReadAllText(file), Encoding.UTF8)); + } + } + finally + { + if (!context.GetKeepGeneratedSources()) + { + Directory.Delete(outputDir, true); + } + } + } + + private void GenerateWinMD(MetadataBuilder metadataBuilder) + { + string outputFile = context.GetWinmdOutputFile(); + Logger.Log("Writing " + outputFile); + var managedPeBuilder = new ManagedPEBuilder( + new PEHeaderBuilder( + machine: Machine.I386, + imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll | Characteristics.Bit32Machine), + new MetadataRootBuilder(metadataBuilder, "WindowsRuntime 1.4"), + new BlobBuilder(), + flags: CorFlags.ILOnly); + + var peBlob = new BlobBuilder(); + managedPeBuilder.Serialize(peBlob); + + using var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write); + peBlob.WriteContentTo(fs); + } + + private bool CatchWinRTDiagnostics() + { + string assemblyName = context.GetAssemblyName(); + WinRTComponentScanner winrtScanner = new(context, assemblyName); + winrtScanner.FindDiagnostics(); + return winrtScanner.Found(); + } + + [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "This method is only setting the exit code, not doing actual file IO.")] + public void Generate() + { + if (CatchWinRTDiagnostics()) + { + Logger.Log("Exiting early -- found errors in authored runtime component."); + Logger.Close(); + Environment.ExitCode = -1; + return; + } + + try + { + string assembly = context.GetAssemblyName(); + string version = context.GetAssemblyVersion(); + MetadataBuilder metadataBuilder = new MetadataBuilder(); + + var writer = new WinRTTypeWriter( + assembly, + version, + metadataBuilder, + Logger, + mapper); + + WinRTSyntaxReceiver syntaxReceiver = (WinRTSyntaxReceiver)context.SyntaxReceiver; + Logger.Log("Found " + syntaxReceiver.Declarations.Count + " types"); + foreach (var declaration in syntaxReceiver.Declarations) + { + writer.Model = context.Compilation.GetSemanticModel(declaration.SyntaxTree); + writer.Visit(declaration); + } + writer.FinalizeGeneration(); + + GenerateWinMD(metadataBuilder); + if (!context.ShouldGenerateWinMDOnly()) + { + GenerateSources(); + writer.GenerateWinRTExposedClassAttributes(context); + } + } + catch (Exception e) + { + Logger.Log(e.ToString()); + if (e.InnerException != null) + { + Logger.Log(e.InnerException.ToString()); + } + Logger.Close(); + Environment.ExitCode = -2; + throw; + } + + Logger.Log("Done"); + Logger.Close(); + } + + private static bool ShouldEmitCallToTryGetDependentActivationFactory(GeneratorExecutionContext context) + { + if (!context.AnalyzerConfigOptions.GetCsWinRTMergeReferencedActivationFactories()) + { + return false; + } + + foreach (MetadataReference metadataReference in context.Compilation.References) + { + if (context.Compilation.GetAssemblyOrModuleSymbol(metadataReference) is not IAssemblySymbol assemblySymbol) + { + continue; + } + + // Check if the current assembly is a WinRT component (we just need one) + if (MergeReferencedActivationFactoriesGenerator.TryGetDependentAssemblyExportsTypeName( + assemblySymbol, + context.Compilation, + CancellationToken.None, + out _)) + { + return true; + } + } + + return false; + } + + /// + /// Generates the native exports for a WinRT component. + /// + /// The value to use to produce source files. + public static void GenerateWinRTNativeExports(GeneratorExecutionContext context) + { + StringBuilder builder = new(); + + builder.AppendLine(""" + // + #pragma warning disable + + namespace WinRT + { + using global::System; + using global::System.Runtime.CompilerServices; + using global::System.Runtime.InteropServices; + + /// + unsafe partial class Module + { + /// + /// Retrieves the activation factory from a DLL that contains activatable Windows Runtime classes. + /// + /// The class identifier that is associated with an activatable runtime class. + /// A pointer to the activation factory that corresponds with the class specified by . + /// The HRESULT for the operation. + /// + [UnmanagedCallersOnly(EntryPoint = nameof(DllGetActivationFactory), CallConvs = new[] { typeof(CallConvStdcall) })] + public static int DllGetActivationFactory(void* activatableClassId, void** factory) + { + const int E_INVALIDARG = unchecked((int)0x80070057); + const int CLASS_E_CLASSNOTAVAILABLE = unchecked((int)(0x80040111)); + const int S_OK = 0; + + if (activatableClassId is null || factory is null) + { + return E_INVALIDARG; + } + + try + { + scoped ReadOnlySpan fullyQualifiedTypeName = MarshalString.FromAbiUnsafe((IntPtr)activatableClassId); + + """); + + // There's three possible cases for this method: + // 1a) The project is a standalone WinRT component + // 1b) The project is a WinRT component, and we're chaining other WinRT components + // 2) The project is an app/library, but we also want to chain other WinRT components + if (context.IsCsWinRTComponent()) + { + builder.AppendLine("IntPtr obj = GetActivationFactory(fullyQualifiedTypeName);"); + builder.AppendLine(); + + // Only emit this call if we have actually generated that. We want to avoid generating + // that default implementation in every single assembly the generator runs on. + if (ShouldEmitCallToTryGetDependentActivationFactory(context)) + { + builder.AppendLine(""" + if ((void*)obj is null) + { + obj = TryGetDependentActivationFactory(fullyQualifiedTypeName); + } + + """); + } + } + else if (ShouldEmitCallToTryGetDependentActivationFactory(context)) + { + builder.AppendLine("IntPtr obj = TryGetDependentActivationFactory(fullyQualifiedTypeName);"); + builder.AppendLine(); + } + + builder.Append(""" + if ((void*)obj is null) + { + *factory = null; + + return CLASS_E_CLASSNOTAVAILABLE; + } + + *factory = (void*)obj; + + return S_OK; + } + catch (Exception e) + { + ExceptionHelpers.SetErrorInfo(e); + + return ExceptionHelpers.GetHRForException(e); + } + } + + /// + /// Determines whether the DLL that implements this function is in use. If not, the caller can unload the DLL from memory. + /// + /// This method always returns S_FALSE. + /// + [UnmanagedCallersOnly(EntryPoint = nameof(DllCanUnloadNow), CallConvs = new[] { typeof(CallConvStdcall) })] + public static int DllCanUnloadNow() + { + const int S_FALSE = 1; + + return S_FALSE; + } + } + } + """); + + context.AddSource("NativeExports.g.cs", builder.ToString()); + } + + /// + /// Generates the native exports for a WinRT component. + /// + /// The value to use to produce source files. + public static void GenerateWinRTExportsType(GeneratorExecutionContext context) + { + if (context.Compilation.AssemblyName is not { Length: > 0 } assemblyName) + { + return; + } + + // If an older CsWinRT version is referenced, it is used to generate the projection. + // The projection generated by it won't be marked partial to generate the attribute on it + // and we also don't support it with the new scenarios without updating CsWinRT package + // So skip generating them. + if (GeneratorHelper.IsOldCsWinRTExe(context)) + { + return; + } + + // Make sure to escape invalid characters for namespace names. + // See ECMA 335, II.6.2 and II.5.2/3. + if (assemblyName.AsSpan().IndexOfAny("$@`?".AsSpan()) != -1) + { + char[] buffer = new char[assemblyName.Length]; + + for (int i = 0; i < assemblyName.Length; i++) + { + buffer[i] = assemblyName[i] is '$' or '@' or '`' or '?' + ? '_' + : assemblyName[i]; + } + + assemblyName = new string(buffer); + } + + context.AddSource("ExportsType.g.cs", $$""" + // + #pragma warning disable + + [assembly: global::WinRT.WinRTAssemblyExportsType(typeof(ABI.Exports.{{assemblyName}}.Module))] + + namespace ABI.Exports.{{assemblyName}} + { + using global::System; + + /// + public static partial class Module + { + /// + public static IntPtr GetActivationFactory(ReadOnlySpan runtimeClassId) + { + return global::WinRT.Module.GetActivationFactory(runtimeClassId); + } + } + } + """); + } + } + + [Generator] + public class SourceGenerator : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) + { + if (!context.IsCsWinRTComponent() && !context.ShouldGenerateWinMDOnly()) + { + // Special case for app/library projects that also want to chain referenced WinRT components. + // This is the case for eg. a UWP app that also has some OOP background tasks. + if (context.ShouldGenerateWinRTNativeExports() && context.GetCsWinRTMergeReferencedActivationFactories()) + { + ComponentGenerator.GenerateWinRTNativeExports(context); + + return; + } + + System.Diagnostics.Debug.WriteLine($"Skipping component {context.GetAssemblyName()}"); + return; + } + + ComponentGenerator generator = new(context); + generator.Generate(); + + // Emit the native exports for NAOT compiled WinRT components, if needed + if (context.IsCsWinRTComponent() && context.ShouldGenerateWinRTNativeExports()) + { + ComponentGenerator.GenerateWinRTNativeExports(context); + } + + // Also emit the unique exported 'Module' type to avoid ambiguities in some scenarios (eg. merging) + if (context.IsCsWinRTComponent()) + { + ComponentGenerator.GenerateWinRTExportsType(context); + } + } + + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(() => new WinRTSyntaxReceiver()); + } + } + + class WinRTSyntaxReceiver : ISyntaxReceiver + { + public List Declarations = new(); + public List Namespaces = new(); + + private bool HasSomePublicTypes(SyntaxNode syntaxNode) + { + return syntaxNode.ChildNodes().OfType().Any(IsPublic); + } + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + // Store namespaces separately as we only need to look at them for diagnostics + // If we did store them in declarations, we would get duplicate entries in the WinMD, + // once from the namespace declaration and once from the member's declaration + if (syntaxNode is NamespaceDeclarationSyntax @namespace) + { + // We only include the namespace if it has a public type as otherwise it won't + // be projected. For partial types, there would be one instance that we encounter + // which declares the accessibility and we will use that to determine the accessibility + // of the type for the purpose of determining whether to include the namespace. + if (HasSomePublicTypes(syntaxNode)) + { + Namespaces.Add(@namespace); + } + + // Subsequent checks will fail, small performance boost to return now. + return; + } + + if (syntaxNode is not MemberDeclarationSyntax declaration || !IsPublicOrPartial(declaration)) + { + return; + } + + if (syntaxNode is ClassDeclarationSyntax || + syntaxNode is InterfaceDeclarationSyntax || + syntaxNode is EnumDeclarationSyntax || + syntaxNode is DelegateDeclarationSyntax || + syntaxNode is StructDeclarationSyntax) + { + Declarations.Add(declaration); + } + } + + private bool IsPublic(MemberDeclarationSyntax member) + { + return member.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)); + } + + private bool IsPublicOrPartial(MemberDeclarationSyntax member) + { + // We detect whether partial types are public using symbol information later. + return member.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword) || m.IsKind(SyntaxKind.PartialKeyword)); + } + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/GenericVtableInitializerStrings.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/GenericVtableInitializerStrings.cs similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/GenericVtableInitializerStrings.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/GenericVtableInitializerStrings.cs index d9d4d048f..fe2fb8b98 100644 --- a/src/Authoring/WinRT.SourceGenerator/GenericVtableInitializerStrings.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/GenericVtableInitializerStrings.cs @@ -1,1738 +1,1738 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Microsoft.CodeAnalysis; -using System.Collections.Immutable; -using System.Linq; -using WinRT.SourceGenerator; - -namespace Generator -{ - internal static class GenericVtableInitializerStrings - { - public static string GetInstantiation(string genericInterface, EquatableArray genericParameters) - { - if (genericInterface == "System.Collections.Generic.IEnumerable`1") - { - return GetIEnumerableInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType); - } - else if (genericInterface == "System.Collections.Generic.IList`1") - { - return GetIListInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType, genericParameters[0].TypeKind); - } - else if (genericInterface == "System.Collections.Generic.IReadOnlyList`1") - { - return GetIReadOnlyListInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType, genericParameters[0].TypeKind); - } - else if (genericInterface == "System.Collections.Generic.IDictionary`2") - { - return GetIDictionaryInstantiation( - genericParameters[0].ProjectedType, - genericParameters[0].AbiType, - genericParameters[0].TypeKind, - genericParameters[1].ProjectedType, - genericParameters[1].AbiType, - genericParameters[1].TypeKind); - } - else if (genericInterface == "System.Collections.Generic.IReadOnlyDictionary`2") - { - return GetIReadOnlyDictionaryInstantiation( - genericParameters[0].ProjectedType, - genericParameters[0].AbiType, - genericParameters[0].TypeKind, - genericParameters[1].ProjectedType, - genericParameters[1].AbiType, - genericParameters[1].TypeKind); - } - else if (genericInterface == "System.Collections.Generic.IEnumerator`1") - { - return GetIEnumeratorInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType, genericParameters[0].TypeKind); - } - else if (genericInterface == "System.Collections.Generic.KeyValuePair`2") - { - return GetKeyValuePairInstantiation( - genericParameters[0].ProjectedType, - genericParameters[0].AbiType, - genericParameters[0].TypeKind, - genericParameters[1].ProjectedType, - genericParameters[1].AbiType, - genericParameters[1].TypeKind); - } - else if (genericInterface == "System.EventHandler`1") - { - return GetEventHandlerInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType, genericParameters[0].TypeKind); - } - else if (genericInterface == "Windows.Foundation.AsyncActionWithProgressCompletedHandler`1") - { - return GetCompletedHandlerInstantiation("Windows.Foundation.AsyncActionWithProgressCompletedHandler", "Windows.Foundation.IAsyncActionWithProgress", genericParameters); - } - else if (genericInterface == "Windows.Foundation.AsyncOperationCompletedHandler`1") - { - return GetCompletedHandlerInstantiation("Windows.Foundation.AsyncOperationCompletedHandler", "Windows.Foundation.IAsyncOperation", genericParameters); - } - else if (genericInterface == "Windows.Foundation.AsyncOperationWithProgressCompletedHandler`2") - { - return GetCompletedHandlerInstantiation("Windows.Foundation.AsyncOperationWithProgressCompletedHandler", "Windows.Foundation.IAsyncOperationWithProgress", genericParameters); - } - else if (genericInterface == "Windows.Foundation.Collections.MapChangedEventHandler`2") - { - string senderInterface = $"global::Windows.Foundation.Collections.IObservableMap<{genericParameters[0].ProjectedType}, {genericParameters[1].ProjectedType}>"; - string changedEventArgsInterface = $"global::Windows.Foundation.Collections.IMapChangedEventArgs<{genericParameters[0].ProjectedType}>"; - return GetChangedHandlerInstantiation("Windows.Foundation.Collections.MapChangedEventHandler", senderInterface, changedEventArgsInterface, genericParameters); - } - else if (genericInterface == "Windows.Foundation.Collections.VectorChangedEventHandler`1") - { - string senderInterface = $"global::Windows.Foundation.Collections.IObservableVector<{genericParameters[0].ProjectedType}>"; - string changedEventArgsInterface = $"global::Windows.Foundation.Collections.IVectorChangedEventArgs"; - return GetChangedHandlerInstantiation("Windows.Foundation.Collections.VectorChangedEventHandler", senderInterface, changedEventArgsInterface, genericParameters); - } - else if (genericInterface == "Windows.Foundation.AsyncActionProgressHandler`1") - { - return GetProgressHandlerInstantiation("Windows.Foundation.AsyncActionProgressHandler", "Windows.Foundation.IAsyncActionWithProgress", genericParameters); - } - else if (genericInterface == "Windows.Foundation.AsyncOperationProgressHandler`2") - { - return GetProgressHandlerInstantiation("Windows.Foundation.AsyncOperationProgressHandler", "Windows.Foundation.IAsyncOperationWithProgress", genericParameters); - } - else if (genericInterface == "Windows.Foundation.TypedEventHandler`2") - { - return GetTypedEventHandlerInstantiation(genericParameters); - } - else if (genericInterface == "Windows.Foundation.IAsyncActionWithProgress`1") - { - return GetIAsyncActionWithProgressInstantiation(genericParameters); - } - else if (genericInterface == "Windows.Foundation.IAsyncOperationWithProgress`2") - { - return GetIAsyncOperationWithProgressInstantiation(genericParameters); - } - else if (genericInterface == "Windows.Foundation.IAsyncOperation`1") - { - return GetIAsyncOperationInstantiation(genericParameters); - } - else if (genericInterface == "Windows.Foundation.Collections.IMapChangedEventArgs`1") - { - return GetIMapChangedEventArgsInstantiation(genericParameters); - } - else if (genericInterface == "Windows.Foundation.Collections.IObservableMap`2") - { - return GetIObservableMapInstantiation(genericParameters); - } - else if (genericInterface == "Windows.Foundation.Collections.IObservableVector`1") - { - return GetIObservableVectorInstantiation(genericParameters); - } - - return ""; - } - - public static ImmutableHashSet AddDependentGenericInterfaces(ImmutableHashSet genericInterfaces) - { - var genericInterfacesList = genericInterfaces.ToList(); - - foreach (var genericInterface in genericInterfaces) - { - if (genericInterface.GenericDefinition == "Windows.Foundation.IAsyncActionWithProgress`1") - { - AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncActionProgressHandler"); - AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncActionWithProgressCompletedHandler"); - } - else if (genericInterface.GenericDefinition == "Windows.Foundation.IAsyncOperationWithProgress`2") - { - AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncOperationProgressHandler"); - AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncOperationWithProgressCompletedHandler"); - } - else if (genericInterface.GenericDefinition == "Windows.Foundation.IAsyncOperation`1") - { - AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncOperationCompletedHandler"); - } - else if (genericInterface.GenericDefinition == "Windows.Foundation.Collections.IObservableMap`2") - { - AddReplacedGenericInterface(genericInterface, "Windows.Foundation.Collections.MapChangedEventHandler"); - } - else if (genericInterface.GenericDefinition == "Windows.Foundation.Collections.IObservableVector`1") - { - AddReplacedGenericInterface(genericInterface, "Windows.Foundation.Collections.VectorChangedEventHandler"); - } - } - - return genericInterfacesList.ToImmutableHashSet(); - - void AddReplacedGenericInterface(GenericInterface genericInterfaceToReplace, string newInterfaceToReplaceWith) - { - // Replace the old interface name with the new one. - // We know this is an generic interface, so we want to replace the string before the generics (<). - string newQualifiedInterfaceName = newInterfaceToReplaceWith + genericInterfaceToReplace.Interface[genericInterfaceToReplace.Interface.IndexOf('<')..]; - - // The metadata name includes the number of generics which we get from the last character of the one we are replacing - // since they are the same in the scenarios we care about. - string newInterfaceMetadataName = newInterfaceToReplaceWith + "`" + genericInterfaceToReplace.GenericDefinition[^1]; - - genericInterfacesList.Add(new GenericInterface( - newQualifiedInterfaceName, - newInterfaceMetadataName, - genericInterfaceToReplace.GenericParameters - )); - } - } - - public static string GetInstantiationInitFunction(string genericInterface, EquatableArray genericParameters, string escapedAssemblyName) - { - // Get the class name from a string like System.Collections.Generic.IEnumerator`1. - // Splitting on the dots and the generic specifier (`) will get us the class name - // in the 2nd last element. - var interfaceName = genericInterface.Split('.', '`')[^2]; - var genericParametersStr = string.Join("_", genericParameters.Select(static genericParameter => GeneratorHelper.EscapeTypeNameForIdentifier(genericParameter.ProjectedType))); - return $$""" _ = global::WinRT.{{escapedAssemblyName}}GenericHelpers.{{interfaceName}}_{{genericParametersStr}}.Initialized;"""; - } - - private static string GetIEnumerableInstantiation(string genericType, string abiType) - { - string iEnumerableInstantiation = $$""" - internal static class IEnumerable_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return global::ABI.System.Collections.Generic.IEnumerableMethods<{{genericType}}, {{abiType}}>.InitCcw( - &Do_Abi_First_0 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_First_0(IntPtr thisPtr, IntPtr* __return_value__) - { - *__return_value__ = default; - try - { - *__return_value__ = MarshalInterface>. - FromManaged(global::ABI.System.Collections.Generic.IEnumerableMethods<{{genericType}}>.Abi_First_0(thisPtr)); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return iEnumerableInstantiation; - } - - private static string GetIEnumeratorInstantiation(string genericType, string abiType, TypeKind typeKind) - { - string iEnumeratorInstantiation = $$""" - internal static class IEnumerator_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}, {{abiType}}>.InitCcw( - &Do_Abi_get_Current_0, - &Do_Abi_get_HasCurrent_1, - &Do_Abi_MoveNext_2, - &Do_Abi_GetMany_3 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_MoveNext_2(IntPtr thisPtr, byte* __return_value__) - { - bool ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}>.Abi_MoveNext_2(thisPtr); - *__return_value__ = (byte)(____return_value__ ? 1 : 0); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetMany_3(IntPtr thisPtr, int __itemsSize, IntPtr items, uint* __return_value__) - { - uint ____return_value__ = default; - - *__return_value__ = default; - {{genericType}}[] __items = {{GeneratorHelper.GetMarshalerClass(genericType, abiType, typeKind, true)}}.FromAbiArray((__itemsSize, items)); - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}>.Abi_GetMany_3(thisPtr, ref __items); - {{GeneratorHelper.GetCopyManagedArrayMarshaler(genericType, abiType, typeKind)}}.CopyManagedArray(__items, items); - *__return_value__ = ____return_value__; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Current_0(IntPtr thisPtr, {{abiType}}* __return_value__) - { - {{genericType}} ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}>.Abi_get_Current_0(thisPtr); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericType, abiType, typeKind, "____return_value__")}}; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_HasCurrent_1(IntPtr thisPtr, byte* __return_value__) - { - bool ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}>.Abi_get_HasCurrent_1(thisPtr); - *__return_value__ = (byte)(____return_value__ ? 1 : 0); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return iEnumeratorInstantiation; - } - - private static string GetIListInstantiation(string genericType, string abiType, TypeKind typeKind) - { - string iListInstantiation = $$""" - internal static class IList_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return global::ABI.System.Collections.Generic.IListMethods<{{genericType}}, {{abiType}}>.InitCcw( - &Do_Abi_GetAt_0, - &Do_Abi_get_Size_1, - &Do_Abi_GetView_2, - &Do_Abi_IndexOf_3, - &Do_Abi_SetAt_4, - &Do_Abi_InsertAt_5, - &Do_Abi_RemoveAt_6, - &Do_Abi_Append_7, - &Do_Abi_RemoveAtEnd_8, - &Do_Abi_Clear_9, - &Do_Abi_GetMany_10, - &Do_Abi_ReplaceAll_11 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetAt_0(IntPtr thisPtr, uint index, {{abiType}}* __return_value__) - { - {{genericType}} ____return_value__ = default; - *__return_value__ = default; - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_GetAt_0(thisPtr, index); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericType, abiType, typeKind, "____return_value__")}}; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetView_2(IntPtr thisPtr, IntPtr* __return_value__) - { - global::System.Collections.Generic.IReadOnlyList<{{genericType}}> ____return_value__ = default; - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_GetView_2(thisPtr); - *__return_value__ = MarshalInterface>.FromManaged(____return_value__); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_IndexOf_3(IntPtr thisPtr, {{abiType}} value, uint* index, byte* __return_value__) - { - bool ____return_value__ = default; - - *index = default; - *__return_value__ = default; - uint __index = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_IndexOf_3(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}, out __index); - *index = __index; - *__return_value__ = (byte)(____return_value__ ? 1 : 0); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_SetAt_4(IntPtr thisPtr, uint index, {{abiType}} value) - { - try - { - global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_SetAt_4(thisPtr, index, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_InsertAt_5(IntPtr thisPtr, uint index, {{abiType}} value) - { - try - { - global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_InsertAt_5(thisPtr, index, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_RemoveAt_6(IntPtr thisPtr, uint index) - { - try - { - global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_RemoveAt_6(thisPtr, index); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Append_7(IntPtr thisPtr, {{abiType}} value) - { - try - { - global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_Append_7(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_RemoveAtEnd_8(IntPtr thisPtr) - { - try - { - global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_RemoveAtEnd_8(thisPtr); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Clear_9(IntPtr thisPtr) - { - try - { - global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_Clear_9(thisPtr); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetMany_10(IntPtr thisPtr, uint startIndex, int __itemsSize, IntPtr items, uint* __return_value__) - { - uint ____return_value__ = default; - - *__return_value__ = default; - {{genericType}}[] __items = {{GeneratorHelper.GetMarshalerClass(genericType, abiType, typeKind, true)}}.FromAbiArray((__itemsSize, items)); - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_GetMany_10(thisPtr, startIndex, ref __items); - {{GeneratorHelper.GetCopyManagedArrayMarshaler(genericType, abiType, typeKind)}}.CopyManagedArray(__items, items); - *__return_value__ = ____return_value__; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_ReplaceAll_11(IntPtr thisPtr, int __itemsSize, IntPtr items) - { - try - { - global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_ReplaceAll_11(thisPtr, {{GeneratorHelper.GetMarshalerClass(genericType, abiType, typeKind, true)}}.FromAbiArray((__itemsSize, items))); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Size_1(IntPtr thisPtr, uint* __return_value__) - { - uint ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_get_Size_1(thisPtr); - *__return_value__ = ____return_value__; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return iListInstantiation; - } - - private static string GetIReadOnlyListInstantiation(string genericType, string abiType, TypeKind typeKind) - { - string iReadOnlylistInstantiation = $$""" - internal static class IReadOnlyList_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}, {{abiType}}>.InitCcw( - &Do_Abi_GetAt_0, - &Do_Abi_get_Size_1, - &Do_Abi_IndexOf_2, - &Do_Abi_GetMany_3 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetAt_0(IntPtr thisPtr, uint index, {{abiType}}* __return_value__) - { - {{genericType}} ____return_value__ = default; - *__return_value__ = default; - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}>.Abi_GetAt_0(thisPtr, index); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericType, abiType, typeKind, "____return_value__")}}; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_IndexOf_2(IntPtr thisPtr, {{abiType}} value, uint* index, byte* __return_value__) - { - bool ____return_value__ = default; - - *index = default; - *__return_value__ = default; - uint __index = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}>.Abi_IndexOf_2(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}, out __index); - *index = __index; - *__return_value__ = (byte)(____return_value__ ? 1 : 0); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetMany_3(IntPtr thisPtr, uint startIndex, int __itemsSize, IntPtr items, uint* __return_value__) - { - uint ____return_value__ = default; - - *__return_value__ = default; - {{genericType}}[] __items = {{GeneratorHelper.GetMarshalerClass(genericType, abiType, typeKind, true)}}.FromAbiArray((__itemsSize, items)); - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}>.Abi_GetMany_3(thisPtr, startIndex, ref __items); - {{GeneratorHelper.GetCopyManagedArrayMarshaler(genericType, abiType, typeKind)}}.CopyManagedArray(__items, items); - *__return_value__ = ____return_value__; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Size_1(IntPtr thisPtr, uint* __return_value__) - { - uint ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}>.Abi_get_Size_1(thisPtr); - *__return_value__ = ____return_value__; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return iReadOnlylistInstantiation; - } - - private static string GetIDictionaryInstantiation(string genericKeyType, string abiKeyType, TypeKind keyTypeKind, string genericValueType, string abiValueType, TypeKind valueTypeKind) - { - string iDictionaryInstantiation = $$""" - internal static class IDictionary_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericKeyType)}}_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericValueType)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{abiKeyType}}, {{genericValueType}}, {{abiValueType}}>.InitCcw( - &Do_Abi_Lookup_0, - &Do_Abi_get_Size_1, - &Do_Abi_HasKey_2, - &Do_Abi_GetView_3, - &Do_Abi_Insert_4, - &Do_Abi_Remove_5, - &Do_Abi_Clear_6 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Lookup_0(IntPtr thisPtr, {{abiKeyType}} key, {{abiValueType}}* __return_value__) - { - {{genericValueType}} ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Lookup_0(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericValueType, abiValueType, valueTypeKind, "____return_value__")}}; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_HasKey_2(IntPtr thisPtr, {{abiKeyType}} key, byte* __return_value__) - { - bool ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_HasKey_2(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); - *__return_value__ = (byte)(____return_value__ ? 1 : 0); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetView_3(IntPtr thisPtr, IntPtr* __return_value__) - { - global::System.Collections.Generic.IReadOnlyDictionary<{{genericKeyType}}, {{genericValueType}}> ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_GetView_3(thisPtr); - *__return_value__ = MarshalInterface>.FromManaged(____return_value__); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Insert_4(IntPtr thisPtr, {{abiKeyType}} key, {{abiValueType}} value, byte* __return_value__) - { - bool ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Insert_4(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}, {{GeneratorHelper.GetFromAbiMarshaler(genericValueType, abiValueType, valueTypeKind, "value")}}); - *__return_value__ = (byte)(____return_value__ ? 1 : 0); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Remove_5(IntPtr thisPtr, {{abiKeyType}} key) - { - try - { - global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Remove_5(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Clear_6(IntPtr thisPtr) - { - try - { - global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Clear_6(thisPtr); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Size_1(IntPtr thisPtr, uint* __return_value__) - { - uint ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_get_Size_1(thisPtr); - *__return_value__ = ____return_value__; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return iDictionaryInstantiation; - } - - private static string GetIReadOnlyDictionaryInstantiation(string genericKeyType, string abiKeyType, TypeKind keyTypeKind, string genericValueType, string abiValueType, TypeKind valueTypeKind) - { - string iReadOnlyDictionaryInstantiation = $$""" - internal static class IReadOnlyDictionary_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericKeyType)}}_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericValueType)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{abiKeyType}}, {{genericValueType}}, {{abiValueType}}>.InitCcw( - &Do_Abi_Lookup_0, - &Do_Abi_get_Size_1, - &Do_Abi_HasKey_2, - &Do_Abi_Split_3 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Lookup_0(IntPtr thisPtr, {{abiKeyType}} key, {{abiValueType}}* __return_value__) - { - {{genericValueType}} ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Lookup_0(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericValueType, abiValueType, valueTypeKind, "____return_value__")}}; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_HasKey_2(IntPtr thisPtr, {{abiKeyType}} key, byte* __return_value__) - { - bool ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_HasKey_2(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); - *__return_value__ = (byte)(____return_value__ ? 1 : 0); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Split_3(IntPtr thisPtr, IntPtr* first, IntPtr* second) - { - *first = default; - *second = default; - IntPtr __first = default; - IntPtr __second = default; - - try - { - global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Split_3(thisPtr, out __first, out __second); - *first = __first; - *second = __second; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Size_1(IntPtr thisPtr, uint* __return_value__) - { - uint ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_get_Size_1(thisPtr); - *__return_value__ = ____return_value__; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return iReadOnlyDictionaryInstantiation; - } - - private static string GetKeyValuePairInstantiation(string genericKeyType, string abiKeyType, TypeKind keyTypeKind, string genericValueType, string abiValueType, TypeKind valueTypeKind) - { - string keyValuePairInstantiation = $$""" - internal static class KeyValuePair_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericKeyType)}}_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericValueType)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return global::ABI.System.Collections.Generic.KeyValuePairMethods<{{genericKeyType}}, {{abiKeyType}}, {{genericValueType}}, {{abiValueType}}>.InitCcw( - &Do_Abi_get_Key_0, - &Do_Abi_get_Value_1 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Key_0(IntPtr thisPtr, {{abiKeyType}}* __return_value__) - { - {{genericKeyType}} ____return_value__ = default; - *__return_value__ = default; - try - { - ____return_value__ = global::ABI.System.Collections.Generic.KeyValuePairMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_get_Key_0(thisPtr); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericKeyType, abiKeyType, keyTypeKind, "____return_value__")}}; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Value_1(IntPtr thisPtr, {{abiValueType}}* __return_value__) - { - {{genericValueType}} ____return_value__ = default; - *__return_value__ = default; - try - { - ____return_value__ = global::ABI.System.Collections.Generic.KeyValuePairMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_get_Value_1(thisPtr); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericValueType, abiValueType, valueTypeKind, "____return_value__")}}; - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return keyValuePairInstantiation; - } - - // Delegates are special and initialize both the RCW and CCW. - private static string GetEventHandlerInstantiation(string genericType, string abiType, TypeKind typeKind) - { - string eventHandlerInstantiation = $$""" - internal static class EventHandler_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - _ = global::ABI.System.EventHandlerMethods<{{genericType}}, {{abiType}}>.InitCcw( - &Do_Abi_Invoke - ); - _ = global::ABI.System.EventHandlerMethods<{{genericType}}, {{abiType}}>.InitRcwHelper( - &Invoke - ); - return true; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, {{abiType}} args) - { - try - { - global::ABI.System.EventHandlerMethods<{{genericType}}, {{abiType}}>.Abi_Invoke(thisPtr, MarshalInspectable.FromAbi(sender), {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "args")}}); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - private static unsafe void Invoke(IObjectReference objRef, object sender, {{genericType}} args) - { - IntPtr ThisPtr = objRef.ThisPtr; - ObjectReferenceValue __sender = default; - {{GeneratorHelper.GetMarshalerDeclaration(genericType, abiType, typeKind, "args")}} - try - { - __sender = MarshalInspectable.CreateMarshaler2(sender); - IntPtr abiSender = MarshalInspectable.GetAbi(__sender); - {{GeneratorHelper.GetCreateMarshaler(genericType, abiType, typeKind, "args")}} - global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)ThisPtr)[3](ThisPtr, abiSender, {{GeneratorHelper.GetAbiFromMarshaler(genericType, abiType, typeKind, "args")}})); - global::System.GC.KeepAlive(objRef); - } - finally - { - MarshalInspectable.DisposeMarshaler(__sender); - {{GeneratorHelper.GetDisposeMarshaler(genericType, abiType, typeKind, "args")}} - } - } - } - """; - return eventHandlerInstantiation; - } - - private static string GetTypedEventHandlerInstantiation(EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.Windows.Foundation.TypedEventHandlerMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string typedEventHandlerInstantiation = $$""" - internal static class TypedEventHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - _ = {{staticMethodsClass}}.InitCcw( - &Do_Abi_Invoke - ); - _ = {{staticMethodsClass}}.InitRcwHelper( - &Invoke - ); - return true; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, {{genericParameters[0].AbiType}} sender, {{genericParameters[1].AbiType}} args) - { - try - { - {{staticMethodsClass}}.Abi_Invoke(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericParameters[0], "sender")}}, {{GeneratorHelper.GetFromAbiMarshaler(genericParameters[1], "args")}}); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - private static unsafe void Invoke(IObjectReference objRef, {{genericParameters[0].ProjectedType}} sender, {{genericParameters[1].ProjectedType}} args) - { - IntPtr ThisPtr = objRef.ThisPtr; - {{GeneratorHelper.GetMarshalerDeclaration(genericParameters[0], "sender")}} - {{GeneratorHelper.GetMarshalerDeclaration(genericParameters[1], "args")}} - try - { - {{GeneratorHelper.GetCreateMarshaler(genericParameters[0], "sender")}} - {{GeneratorHelper.GetCreateMarshaler(genericParameters[1], "args")}} - global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)ThisPtr)[3](ThisPtr, {{GeneratorHelper.GetAbiFromMarshaler(genericParameters[0], "sender")}}, {{GeneratorHelper.GetAbiFromMarshaler(genericParameters[1], "args")}})); - global::System.GC.KeepAlive(objRef); - } - finally - { - {{GeneratorHelper.GetDisposeMarshaler(genericParameters[0], "sender")}} - {{GeneratorHelper.GetDisposeMarshaler(genericParameters[1], "args")}} - } - } - } - """; - return typedEventHandlerInstantiation; - } - - private static string GetCompletedHandlerInstantiation(string completedHandler, string asyncInfoInterface, EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.{completedHandler}Methods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string interfaceWithGeneric = $"global::{asyncInfoInterface}<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; - string completedHandlerInstantiation = $$""" - internal static class {{completedHandler.Split('.')[^1]}}_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return {{staticMethodsClass}}.InitCcw( - &Do_Abi_Invoke - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr asyncInfo, global::Windows.Foundation.AsyncStatus asyncStatus) - { - try - { - {{staticMethodsClass}}.Abi_Invoke(thisPtr, MarshalInterface<{{interfaceWithGeneric}}>.FromAbi(asyncInfo), asyncStatus); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return completedHandlerInstantiation; - } - - private static string GetChangedHandlerInstantiation(string changedHandler, string senderInterface, string changedEventArgsInterface, EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.{changedHandler}Methods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string changedHandlerInstantiation = $$""" - internal static class {{changedHandler.Split('.')[^1]}}_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return {{staticMethodsClass}}.InitCcw( - &Do_Abi_Invoke - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr @event) - { - try - { - {{staticMethodsClass}}.Abi_Invoke(thisPtr, MarshalInterface<{{senderInterface}}>.FromAbi(sender), MarshalInterface<{{changedEventArgsInterface}}>.FromAbi(@event)); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return changedHandlerInstantiation; - } - - private static string GetProgressHandlerInstantiation(string progressHandler, string asyncInfoInterface, EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.{progressHandler}Methods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string asyncInfoInterfaceWithGeneric = $"global::{asyncInfoInterface}<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; - string asyncInfoInterfaceWithGenericMethodsClass = $"global::ABI.{asyncInfoInterface}Methods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; - var progressParameter = genericParameters.Last(); - string progressHandlerInstantiation = $$""" - internal static class {{progressHandler.Split('.')[^1]}}_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - _ = {{staticMethodsClass}}.InitCcw( - &Do_Abi_Invoke - ); - _ = {{staticMethodsClass}}.InitRcwHelper( - &Invoke - ); - return true; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr asyncInfo, {{progressParameter.AbiType}} progressInfo) - { - try - { - {{staticMethodsClass}}.Abi_Invoke(thisPtr, MarshalInterface<{{asyncInfoInterfaceWithGeneric}}>.FromAbi(asyncInfo), {{GeneratorHelper.GetFromAbiMarshaler(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}}); - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - private static unsafe void Invoke(IObjectReference objRef, {{asyncInfoInterfaceWithGeneric}} asyncInfo, {{progressParameter.ProjectedType}} progressInfo) - { - IntPtr ThisPtr = objRef.ThisPtr; - ObjectReferenceValue __asyncInfo = default; - {{GeneratorHelper.GetMarshalerDeclaration(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}} - try - { - __asyncInfo = MarshalInterface<{{asyncInfoInterfaceWithGeneric}}>.CreateMarshaler2(asyncInfo, {{asyncInfoInterfaceWithGenericMethodsClass}}.IID); - IntPtr abiAsyncInfo = MarshalInspectable.GetAbi(__asyncInfo); - {{GeneratorHelper.GetCreateMarshaler(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}} - global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)ThisPtr)[3](ThisPtr, abiAsyncInfo, {{GeneratorHelper.GetAbiFromMarshaler(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}})); - global::System.GC.KeepAlive(objRef); - } - finally - { - MarshalInterface<{{asyncInfoInterfaceWithGeneric}}>.DisposeMarshaler(__asyncInfo); - {{GeneratorHelper.GetDisposeMarshaler(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}} - } - } - } - """; - return progressHandlerInstantiation; - } - - private static string GetIAsyncActionWithProgressInstantiation(EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncActionWithProgressMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; - string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncActionWithProgressMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string instantiation = $$""" - internal static class IAsyncActionWithProgress_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return {{abiStaticMethodsClass}}.InitCcw( - &Do_Abi_put_Progress_0, - &Do_Abi_get_Progress_1, - &Do_Abi_put_Completed_2, - &Do_Abi_get_Completed_3, - &Do_Abi_GetResults_4 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetResults_4(IntPtr thisPtr) - { - try - { - {{staticMethodsClass}}.Do_Abi_GetResults_4(thisPtr); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_put_Progress_0(IntPtr thisPtr, IntPtr handler) - { - _ = AsyncActionProgressHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - try - { - {{staticMethodsClass}}.Do_Abi_put_Progress_0(thisPtr, global::ABI.Windows.Foundation.AsyncActionProgressHandler<{{genericParameters[0].ProjectedType}}>.FromAbi(handler)); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Progress_1(IntPtr thisPtr, IntPtr* __return_value__) - { - _ = AsyncActionProgressHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - global::Windows.Foundation.AsyncActionProgressHandler<{{genericParameters[0].ProjectedType}}> ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Progress_1(thisPtr); - *__return_value__ = global::ABI.Windows.Foundation.AsyncActionProgressHandler<{{genericParameters[0].ProjectedType}}>.FromManaged(____return_value__); - - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_put_Completed_2(IntPtr thisPtr, IntPtr handler) - { - _ = AsyncActionWithProgressCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - try - { - {{staticMethodsClass}}.Do_Abi_put_Completed_2(thisPtr, global::ABI.Windows.Foundation.AsyncActionWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}>.FromAbi(handler)); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Completed_3(IntPtr thisPtr, IntPtr* __return_value__) - { - _ = AsyncActionWithProgressCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - global::Windows.Foundation.AsyncActionWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}> ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Completed_3(thisPtr); - *__return_value__ = global::ABI.Windows.Foundation.AsyncActionWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}>.FromManaged(____return_value__); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return instantiation; - } - - private static string GetIAsyncOperationWithProgressInstantiation(EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncOperationWithProgressMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; - string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncOperationWithProgressMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string instantiation = $$""" - internal static class IAsyncOperationWithProgress_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return {{abiStaticMethodsClass}}.InitCcw( - &Do_Abi_put_Progress_0, - &Do_Abi_get_Progress_1, - &Do_Abi_put_Completed_2, - &Do_Abi_get_Completed_3, - &Do_Abi_GetResults_4 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetResults_4(IntPtr thisPtr, {{genericParameters[0].AbiType}}* __return_value__) - { - {{genericParameters[0].ProjectedType}} ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = {{staticMethodsClass}}.Do_Abi_GetResults_4(thisPtr); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericParameters[0], "____return_value__")}}; - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_put_Progress_0(IntPtr thisPtr, IntPtr handler) - { - _ = AsyncOperationProgressHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - try - { - {{staticMethodsClass}}.Do_Abi_put_Progress_0(thisPtr, global::ABI.Windows.Foundation.AsyncOperationProgressHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromAbi(handler)); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Progress_1(IntPtr thisPtr, IntPtr* __return_value__) - { - _ = AsyncOperationProgressHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - global::Windows.Foundation.AsyncOperationProgressHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}> ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Progress_1(thisPtr); - *__return_value__ = global::ABI.Windows.Foundation.AsyncOperationProgressHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromManaged(____return_value__); - - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_put_Completed_2(IntPtr thisPtr, IntPtr handler) - { - _ = AsyncOperationWithProgressCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - try - { - {{staticMethodsClass}}.Do_Abi_put_Completed_2(thisPtr, global::ABI.Windows.Foundation.AsyncOperationWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromAbi(handler)); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Completed_3(IntPtr thisPtr, IntPtr* __return_value__) - { - _ = AsyncOperationWithProgressCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - global::Windows.Foundation.AsyncOperationWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}> ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Completed_3(thisPtr); - *__return_value__ = global::ABI.Windows.Foundation.AsyncOperationWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromManaged(____return_value__); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return instantiation; - } - - private static string GetIAsyncOperationInstantiation(EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncOperationMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; - string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncOperationMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string instantiation = $$""" - internal static class IAsyncOperation_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return {{abiStaticMethodsClass}}.InitCcw( - &Do_Abi_put_Completed_0, - &Do_Abi_get_Completed_1, - &Do_Abi_GetResults_2 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_GetResults_2(IntPtr thisPtr, {{genericParameters[0].AbiType}}* __return_value__) - { - {{genericParameters[0].ProjectedType}} ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = {{staticMethodsClass}}.Do_Abi_GetResults_2(thisPtr); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericParameters[0], "____return_value__")}}; - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_put_Completed_0(IntPtr thisPtr, IntPtr handler) - { - _ = AsyncOperationCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - try - { - {{staticMethodsClass}}.Do_Abi_put_Completed_0(thisPtr, global::ABI.Windows.Foundation.AsyncOperationCompletedHandler<{{genericParameters[0].ProjectedType}}>.FromAbi(handler)); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Completed_1(IntPtr thisPtr, IntPtr* __return_value__) - { - _ = AsyncOperationCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - global::Windows.Foundation.AsyncOperationCompletedHandler<{{genericParameters[0].ProjectedType}}> ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Completed_1(thisPtr); - *__return_value__ = global::ABI.Windows.Foundation.AsyncOperationCompletedHandler<{{genericParameters[0].ProjectedType}}>.FromManaged(____return_value__); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return instantiation; - } - - private static string GetIMapChangedEventArgsInstantiation(EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IMapChangedEventArgsMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; - string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IMapChangedEventArgsMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string instantiation = $$""" - internal static class IMapChangedEventArgs_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return {{abiStaticMethodsClass}}.InitCcw( - &Do_Abi_get_CollectionChange_0, - &Do_Abi_get_Key_1 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_CollectionChange_0(IntPtr thisPtr, global::Windows.Foundation.Collections.CollectionChange* __return_value__) - { - *__return_value__ = default; - - try - { - *__return_value__ = {{staticMethodsClass}}.Do_Abi_get_CollectionChange_0(thisPtr); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_get_Key_1(IntPtr thisPtr, {{genericParameters[0].AbiType}}* __return_value__) - { - {{genericParameters[0].ProjectedType}} ____return_value__ = default; - - *__return_value__ = default; - - try - { - ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Key_1(thisPtr); - *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericParameters[0], "____return_value__")}}; - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return instantiation; - } - - private static string GetIObservableMapInstantiation(EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IObservableMapMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; - string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IObservableMapMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string instantiation = $$""" - internal static class IObservableMap_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return {{abiStaticMethodsClass}}.InitCcw( - &Do_Abi_add_MapChanged_0, - &Do_Abi_remove_MapChanged_1 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_add_MapChanged_0(IntPtr thisPtr, IntPtr vhnd, global::WinRT.EventRegistrationToken* __return_value__) - { - *__return_value__ = default; - _ = MapChangedEventHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - try - { - *__return_value__ = {{staticMethodsClass}}.Do_Abi_add_MapChanged_0(thisPtr, global::ABI.Windows.Foundation.Collections.MapChangedEventHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromAbi(vhnd)); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_remove_MapChanged_1(IntPtr thisPtr, global::WinRT.EventRegistrationToken token) - { - try - { - {{staticMethodsClass}}.Do_Abi_remove_MapChanged_1(thisPtr, token); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return instantiation; - } - - private static string GetIObservableVectorInstantiation(EquatableArray genericParameters) - { - string staticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IObservableVectorMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; - string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IObservableVectorMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; - string instantiation = $$""" - internal static class IObservableVector_{{GetGenericParametersAsString(genericParameters, "_", false)}} - { - private static readonly bool _initialized = Init(); - internal static bool Initialized => _initialized; - - private static unsafe bool Init() - { - return {{abiStaticMethodsClass}}.InitCcw( - &Do_Abi_add_VectorChanged_0, - &Do_Abi_remove_VectorChanged_1 - ); - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_add_VectorChanged_0(IntPtr thisPtr, IntPtr vhnd, global::WinRT.EventRegistrationToken* __return_value__) - { - *__return_value__ = default; - _ = VectorChangedEventHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; - try - { - *__return_value__ = {{staticMethodsClass}}.Do_Abi_add_VectorChanged_0(thisPtr, global::ABI.Windows.Foundation.Collections.VectorChangedEventHandler<{{genericParameters[0].ProjectedType}}>.FromAbi(vhnd)); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] - private static unsafe int Do_Abi_remove_VectorChanged_1(IntPtr thisPtr, global::WinRT.EventRegistrationToken token) - { - try - { - {{staticMethodsClass}}.Do_Abi_remove_VectorChanged_1(thisPtr, token); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - """; - return instantiation; - } - - private static string GetGenericParametersAsString(EquatableArray genericParameters, string separator, bool includeAbiTypes, bool escape = true) - { - string genericParametersStr = string.Join(separator, - genericParameters.Select(genericParameter => - { - if (includeAbiTypes) - { - return string.Join( - separator, - escape ? GeneratorHelper.EscapeTypeNameForIdentifier(genericParameter.ProjectedType) : genericParameter.ProjectedType, - escape ? GeneratorHelper.EscapeTypeNameForIdentifier(genericParameter.AbiType) : genericParameter.AbiType); - } - else - { - return escape ? GeneratorHelper.EscapeTypeNameForIdentifier(genericParameter.ProjectedType) : genericParameter.ProjectedType; - } - })); - return genericParametersStr; - } - } -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.CodeAnalysis; +using System.Collections.Immutable; +using System.Linq; +using WinRT.SourceGenerator; + +namespace Generator +{ + internal static class GenericVtableInitializerStrings + { + public static string GetInstantiation(string genericInterface, EquatableArray genericParameters) + { + if (genericInterface == "System.Collections.Generic.IEnumerable`1") + { + return GetIEnumerableInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType); + } + else if (genericInterface == "System.Collections.Generic.IList`1") + { + return GetIListInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType, genericParameters[0].TypeKind); + } + else if (genericInterface == "System.Collections.Generic.IReadOnlyList`1") + { + return GetIReadOnlyListInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType, genericParameters[0].TypeKind); + } + else if (genericInterface == "System.Collections.Generic.IDictionary`2") + { + return GetIDictionaryInstantiation( + genericParameters[0].ProjectedType, + genericParameters[0].AbiType, + genericParameters[0].TypeKind, + genericParameters[1].ProjectedType, + genericParameters[1].AbiType, + genericParameters[1].TypeKind); + } + else if (genericInterface == "System.Collections.Generic.IReadOnlyDictionary`2") + { + return GetIReadOnlyDictionaryInstantiation( + genericParameters[0].ProjectedType, + genericParameters[0].AbiType, + genericParameters[0].TypeKind, + genericParameters[1].ProjectedType, + genericParameters[1].AbiType, + genericParameters[1].TypeKind); + } + else if (genericInterface == "System.Collections.Generic.IEnumerator`1") + { + return GetIEnumeratorInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType, genericParameters[0].TypeKind); + } + else if (genericInterface == "System.Collections.Generic.KeyValuePair`2") + { + return GetKeyValuePairInstantiation( + genericParameters[0].ProjectedType, + genericParameters[0].AbiType, + genericParameters[0].TypeKind, + genericParameters[1].ProjectedType, + genericParameters[1].AbiType, + genericParameters[1].TypeKind); + } + else if (genericInterface == "System.EventHandler`1") + { + return GetEventHandlerInstantiation(genericParameters[0].ProjectedType, genericParameters[0].AbiType, genericParameters[0].TypeKind); + } + else if (genericInterface == "Windows.Foundation.AsyncActionWithProgressCompletedHandler`1") + { + return GetCompletedHandlerInstantiation("Windows.Foundation.AsyncActionWithProgressCompletedHandler", "Windows.Foundation.IAsyncActionWithProgress", genericParameters); + } + else if (genericInterface == "Windows.Foundation.AsyncOperationCompletedHandler`1") + { + return GetCompletedHandlerInstantiation("Windows.Foundation.AsyncOperationCompletedHandler", "Windows.Foundation.IAsyncOperation", genericParameters); + } + else if (genericInterface == "Windows.Foundation.AsyncOperationWithProgressCompletedHandler`2") + { + return GetCompletedHandlerInstantiation("Windows.Foundation.AsyncOperationWithProgressCompletedHandler", "Windows.Foundation.IAsyncOperationWithProgress", genericParameters); + } + else if (genericInterface == "Windows.Foundation.Collections.MapChangedEventHandler`2") + { + string senderInterface = $"global::Windows.Foundation.Collections.IObservableMap<{genericParameters[0].ProjectedType}, {genericParameters[1].ProjectedType}>"; + string changedEventArgsInterface = $"global::Windows.Foundation.Collections.IMapChangedEventArgs<{genericParameters[0].ProjectedType}>"; + return GetChangedHandlerInstantiation("Windows.Foundation.Collections.MapChangedEventHandler", senderInterface, changedEventArgsInterface, genericParameters); + } + else if (genericInterface == "Windows.Foundation.Collections.VectorChangedEventHandler`1") + { + string senderInterface = $"global::Windows.Foundation.Collections.IObservableVector<{genericParameters[0].ProjectedType}>"; + string changedEventArgsInterface = $"global::Windows.Foundation.Collections.IVectorChangedEventArgs"; + return GetChangedHandlerInstantiation("Windows.Foundation.Collections.VectorChangedEventHandler", senderInterface, changedEventArgsInterface, genericParameters); + } + else if (genericInterface == "Windows.Foundation.AsyncActionProgressHandler`1") + { + return GetProgressHandlerInstantiation("Windows.Foundation.AsyncActionProgressHandler", "Windows.Foundation.IAsyncActionWithProgress", genericParameters); + } + else if (genericInterface == "Windows.Foundation.AsyncOperationProgressHandler`2") + { + return GetProgressHandlerInstantiation("Windows.Foundation.AsyncOperationProgressHandler", "Windows.Foundation.IAsyncOperationWithProgress", genericParameters); + } + else if (genericInterface == "Windows.Foundation.TypedEventHandler`2") + { + return GetTypedEventHandlerInstantiation(genericParameters); + } + else if (genericInterface == "Windows.Foundation.IAsyncActionWithProgress`1") + { + return GetIAsyncActionWithProgressInstantiation(genericParameters); + } + else if (genericInterface == "Windows.Foundation.IAsyncOperationWithProgress`2") + { + return GetIAsyncOperationWithProgressInstantiation(genericParameters); + } + else if (genericInterface == "Windows.Foundation.IAsyncOperation`1") + { + return GetIAsyncOperationInstantiation(genericParameters); + } + else if (genericInterface == "Windows.Foundation.Collections.IMapChangedEventArgs`1") + { + return GetIMapChangedEventArgsInstantiation(genericParameters); + } + else if (genericInterface == "Windows.Foundation.Collections.IObservableMap`2") + { + return GetIObservableMapInstantiation(genericParameters); + } + else if (genericInterface == "Windows.Foundation.Collections.IObservableVector`1") + { + return GetIObservableVectorInstantiation(genericParameters); + } + + return ""; + } + + public static ImmutableHashSet AddDependentGenericInterfaces(ImmutableHashSet genericInterfaces) + { + var genericInterfacesList = genericInterfaces.ToList(); + + foreach (var genericInterface in genericInterfaces) + { + if (genericInterface.GenericDefinition == "Windows.Foundation.IAsyncActionWithProgress`1") + { + AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncActionProgressHandler"); + AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncActionWithProgressCompletedHandler"); + } + else if (genericInterface.GenericDefinition == "Windows.Foundation.IAsyncOperationWithProgress`2") + { + AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncOperationProgressHandler"); + AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncOperationWithProgressCompletedHandler"); + } + else if (genericInterface.GenericDefinition == "Windows.Foundation.IAsyncOperation`1") + { + AddReplacedGenericInterface(genericInterface, "Windows.Foundation.AsyncOperationCompletedHandler"); + } + else if (genericInterface.GenericDefinition == "Windows.Foundation.Collections.IObservableMap`2") + { + AddReplacedGenericInterface(genericInterface, "Windows.Foundation.Collections.MapChangedEventHandler"); + } + else if (genericInterface.GenericDefinition == "Windows.Foundation.Collections.IObservableVector`1") + { + AddReplacedGenericInterface(genericInterface, "Windows.Foundation.Collections.VectorChangedEventHandler"); + } + } + + return genericInterfacesList.ToImmutableHashSet(); + + void AddReplacedGenericInterface(GenericInterface genericInterfaceToReplace, string newInterfaceToReplaceWith) + { + // Replace the old interface name with the new one. + // We know this is an generic interface, so we want to replace the string before the generics (<). + string newQualifiedInterfaceName = newInterfaceToReplaceWith + genericInterfaceToReplace.Interface[genericInterfaceToReplace.Interface.IndexOf('<')..]; + + // The metadata name includes the number of generics which we get from the last character of the one we are replacing + // since they are the same in the scenarios we care about. + string newInterfaceMetadataName = newInterfaceToReplaceWith + "`" + genericInterfaceToReplace.GenericDefinition[^1]; + + genericInterfacesList.Add(new GenericInterface( + newQualifiedInterfaceName, + newInterfaceMetadataName, + genericInterfaceToReplace.GenericParameters + )); + } + } + + public static string GetInstantiationInitFunction(string genericInterface, EquatableArray genericParameters, string escapedAssemblyName) + { + // Get the class name from a string like System.Collections.Generic.IEnumerator`1. + // Splitting on the dots and the generic specifier (`) will get us the class name + // in the 2nd last element. + var interfaceName = genericInterface.Split('.', '`')[^2]; + var genericParametersStr = string.Join("_", genericParameters.Select(static genericParameter => GeneratorHelper.EscapeTypeNameForIdentifier(genericParameter.ProjectedType))); + return $$""" _ = global::WinRT.{{escapedAssemblyName}}GenericHelpers.{{interfaceName}}_{{genericParametersStr}}.Initialized;"""; + } + + private static string GetIEnumerableInstantiation(string genericType, string abiType) + { + string iEnumerableInstantiation = $$""" + internal static class IEnumerable_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return global::ABI.System.Collections.Generic.IEnumerableMethods<{{genericType}}, {{abiType}}>.InitCcw( + &Do_Abi_First_0 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_First_0(IntPtr thisPtr, IntPtr* __return_value__) + { + *__return_value__ = default; + try + { + *__return_value__ = MarshalInterface>. + FromManaged(global::ABI.System.Collections.Generic.IEnumerableMethods<{{genericType}}>.Abi_First_0(thisPtr)); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return iEnumerableInstantiation; + } + + private static string GetIEnumeratorInstantiation(string genericType, string abiType, TypeKind typeKind) + { + string iEnumeratorInstantiation = $$""" + internal static class IEnumerator_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}, {{abiType}}>.InitCcw( + &Do_Abi_get_Current_0, + &Do_Abi_get_HasCurrent_1, + &Do_Abi_MoveNext_2, + &Do_Abi_GetMany_3 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_MoveNext_2(IntPtr thisPtr, byte* __return_value__) + { + bool ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}>.Abi_MoveNext_2(thisPtr); + *__return_value__ = (byte)(____return_value__ ? 1 : 0); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetMany_3(IntPtr thisPtr, int __itemsSize, IntPtr items, uint* __return_value__) + { + uint ____return_value__ = default; + + *__return_value__ = default; + {{genericType}}[] __items = {{GeneratorHelper.GetMarshalerClass(genericType, abiType, typeKind, true)}}.FromAbiArray((__itemsSize, items)); + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}>.Abi_GetMany_3(thisPtr, ref __items); + {{GeneratorHelper.GetCopyManagedArrayMarshaler(genericType, abiType, typeKind)}}.CopyManagedArray(__items, items); + *__return_value__ = ____return_value__; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Current_0(IntPtr thisPtr, {{abiType}}* __return_value__) + { + {{genericType}} ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}>.Abi_get_Current_0(thisPtr); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericType, abiType, typeKind, "____return_value__")}}; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_HasCurrent_1(IntPtr thisPtr, byte* __return_value__) + { + bool ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IEnumeratorMethods<{{genericType}}>.Abi_get_HasCurrent_1(thisPtr); + *__return_value__ = (byte)(____return_value__ ? 1 : 0); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return iEnumeratorInstantiation; + } + + private static string GetIListInstantiation(string genericType, string abiType, TypeKind typeKind) + { + string iListInstantiation = $$""" + internal static class IList_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return global::ABI.System.Collections.Generic.IListMethods<{{genericType}}, {{abiType}}>.InitCcw( + &Do_Abi_GetAt_0, + &Do_Abi_get_Size_1, + &Do_Abi_GetView_2, + &Do_Abi_IndexOf_3, + &Do_Abi_SetAt_4, + &Do_Abi_InsertAt_5, + &Do_Abi_RemoveAt_6, + &Do_Abi_Append_7, + &Do_Abi_RemoveAtEnd_8, + &Do_Abi_Clear_9, + &Do_Abi_GetMany_10, + &Do_Abi_ReplaceAll_11 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetAt_0(IntPtr thisPtr, uint index, {{abiType}}* __return_value__) + { + {{genericType}} ____return_value__ = default; + *__return_value__ = default; + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_GetAt_0(thisPtr, index); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericType, abiType, typeKind, "____return_value__")}}; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetView_2(IntPtr thisPtr, IntPtr* __return_value__) + { + global::System.Collections.Generic.IReadOnlyList<{{genericType}}> ____return_value__ = default; + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_GetView_2(thisPtr); + *__return_value__ = MarshalInterface>.FromManaged(____return_value__); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_IndexOf_3(IntPtr thisPtr, {{abiType}} value, uint* index, byte* __return_value__) + { + bool ____return_value__ = default; + + *index = default; + *__return_value__ = default; + uint __index = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_IndexOf_3(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}, out __index); + *index = __index; + *__return_value__ = (byte)(____return_value__ ? 1 : 0); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_SetAt_4(IntPtr thisPtr, uint index, {{abiType}} value) + { + try + { + global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_SetAt_4(thisPtr, index, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_InsertAt_5(IntPtr thisPtr, uint index, {{abiType}} value) + { + try + { + global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_InsertAt_5(thisPtr, index, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_RemoveAt_6(IntPtr thisPtr, uint index) + { + try + { + global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_RemoveAt_6(thisPtr, index); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Append_7(IntPtr thisPtr, {{abiType}} value) + { + try + { + global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_Append_7(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_RemoveAtEnd_8(IntPtr thisPtr) + { + try + { + global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_RemoveAtEnd_8(thisPtr); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Clear_9(IntPtr thisPtr) + { + try + { + global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_Clear_9(thisPtr); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetMany_10(IntPtr thisPtr, uint startIndex, int __itemsSize, IntPtr items, uint* __return_value__) + { + uint ____return_value__ = default; + + *__return_value__ = default; + {{genericType}}[] __items = {{GeneratorHelper.GetMarshalerClass(genericType, abiType, typeKind, true)}}.FromAbiArray((__itemsSize, items)); + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_GetMany_10(thisPtr, startIndex, ref __items); + {{GeneratorHelper.GetCopyManagedArrayMarshaler(genericType, abiType, typeKind)}}.CopyManagedArray(__items, items); + *__return_value__ = ____return_value__; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_ReplaceAll_11(IntPtr thisPtr, int __itemsSize, IntPtr items) + { + try + { + global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_ReplaceAll_11(thisPtr, {{GeneratorHelper.GetMarshalerClass(genericType, abiType, typeKind, true)}}.FromAbiArray((__itemsSize, items))); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Size_1(IntPtr thisPtr, uint* __return_value__) + { + uint ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IListMethods<{{genericType}}>.Abi_get_Size_1(thisPtr); + *__return_value__ = ____return_value__; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return iListInstantiation; + } + + private static string GetIReadOnlyListInstantiation(string genericType, string abiType, TypeKind typeKind) + { + string iReadOnlylistInstantiation = $$""" + internal static class IReadOnlyList_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}, {{abiType}}>.InitCcw( + &Do_Abi_GetAt_0, + &Do_Abi_get_Size_1, + &Do_Abi_IndexOf_2, + &Do_Abi_GetMany_3 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetAt_0(IntPtr thisPtr, uint index, {{abiType}}* __return_value__) + { + {{genericType}} ____return_value__ = default; + *__return_value__ = default; + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}>.Abi_GetAt_0(thisPtr, index); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericType, abiType, typeKind, "____return_value__")}}; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_IndexOf_2(IntPtr thisPtr, {{abiType}} value, uint* index, byte* __return_value__) + { + bool ____return_value__ = default; + + *index = default; + *__return_value__ = default; + uint __index = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}>.Abi_IndexOf_2(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "value")}}, out __index); + *index = __index; + *__return_value__ = (byte)(____return_value__ ? 1 : 0); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetMany_3(IntPtr thisPtr, uint startIndex, int __itemsSize, IntPtr items, uint* __return_value__) + { + uint ____return_value__ = default; + + *__return_value__ = default; + {{genericType}}[] __items = {{GeneratorHelper.GetMarshalerClass(genericType, abiType, typeKind, true)}}.FromAbiArray((__itemsSize, items)); + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}>.Abi_GetMany_3(thisPtr, startIndex, ref __items); + {{GeneratorHelper.GetCopyManagedArrayMarshaler(genericType, abiType, typeKind)}}.CopyManagedArray(__items, items); + *__return_value__ = ____return_value__; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Size_1(IntPtr thisPtr, uint* __return_value__) + { + uint ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyListMethods<{{genericType}}>.Abi_get_Size_1(thisPtr); + *__return_value__ = ____return_value__; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return iReadOnlylistInstantiation; + } + + private static string GetIDictionaryInstantiation(string genericKeyType, string abiKeyType, TypeKind keyTypeKind, string genericValueType, string abiValueType, TypeKind valueTypeKind) + { + string iDictionaryInstantiation = $$""" + internal static class IDictionary_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericKeyType)}}_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericValueType)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{abiKeyType}}, {{genericValueType}}, {{abiValueType}}>.InitCcw( + &Do_Abi_Lookup_0, + &Do_Abi_get_Size_1, + &Do_Abi_HasKey_2, + &Do_Abi_GetView_3, + &Do_Abi_Insert_4, + &Do_Abi_Remove_5, + &Do_Abi_Clear_6 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Lookup_0(IntPtr thisPtr, {{abiKeyType}} key, {{abiValueType}}* __return_value__) + { + {{genericValueType}} ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Lookup_0(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericValueType, abiValueType, valueTypeKind, "____return_value__")}}; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_HasKey_2(IntPtr thisPtr, {{abiKeyType}} key, byte* __return_value__) + { + bool ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_HasKey_2(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); + *__return_value__ = (byte)(____return_value__ ? 1 : 0); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetView_3(IntPtr thisPtr, IntPtr* __return_value__) + { + global::System.Collections.Generic.IReadOnlyDictionary<{{genericKeyType}}, {{genericValueType}}> ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_GetView_3(thisPtr); + *__return_value__ = MarshalInterface>.FromManaged(____return_value__); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Insert_4(IntPtr thisPtr, {{abiKeyType}} key, {{abiValueType}} value, byte* __return_value__) + { + bool ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Insert_4(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}, {{GeneratorHelper.GetFromAbiMarshaler(genericValueType, abiValueType, valueTypeKind, "value")}}); + *__return_value__ = (byte)(____return_value__ ? 1 : 0); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Remove_5(IntPtr thisPtr, {{abiKeyType}} key) + { + try + { + global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Remove_5(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Clear_6(IntPtr thisPtr) + { + try + { + global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Clear_6(thisPtr); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Size_1(IntPtr thisPtr, uint* __return_value__) + { + uint ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_get_Size_1(thisPtr); + *__return_value__ = ____return_value__; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return iDictionaryInstantiation; + } + + private static string GetIReadOnlyDictionaryInstantiation(string genericKeyType, string abiKeyType, TypeKind keyTypeKind, string genericValueType, string abiValueType, TypeKind valueTypeKind) + { + string iReadOnlyDictionaryInstantiation = $$""" + internal static class IReadOnlyDictionary_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericKeyType)}}_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericValueType)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{abiKeyType}}, {{genericValueType}}, {{abiValueType}}>.InitCcw( + &Do_Abi_Lookup_0, + &Do_Abi_get_Size_1, + &Do_Abi_HasKey_2, + &Do_Abi_Split_3 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Lookup_0(IntPtr thisPtr, {{abiKeyType}} key, {{abiValueType}}* __return_value__) + { + {{genericValueType}} ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Lookup_0(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericValueType, abiValueType, valueTypeKind, "____return_value__")}}; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_HasKey_2(IntPtr thisPtr, {{abiKeyType}} key, byte* __return_value__) + { + bool ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_HasKey_2(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericKeyType, abiKeyType, keyTypeKind, "key")}}); + *__return_value__ = (byte)(____return_value__ ? 1 : 0); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Split_3(IntPtr thisPtr, IntPtr* first, IntPtr* second) + { + *first = default; + *second = default; + IntPtr __first = default; + IntPtr __second = default; + + try + { + global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_Split_3(thisPtr, out __first, out __second); + *first = __first; + *second = __second; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Size_1(IntPtr thisPtr, uint* __return_value__) + { + uint ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = global::ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_get_Size_1(thisPtr); + *__return_value__ = ____return_value__; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return iReadOnlyDictionaryInstantiation; + } + + private static string GetKeyValuePairInstantiation(string genericKeyType, string abiKeyType, TypeKind keyTypeKind, string genericValueType, string abiValueType, TypeKind valueTypeKind) + { + string keyValuePairInstantiation = $$""" + internal static class KeyValuePair_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericKeyType)}}_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericValueType)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return global::ABI.System.Collections.Generic.KeyValuePairMethods<{{genericKeyType}}, {{abiKeyType}}, {{genericValueType}}, {{abiValueType}}>.InitCcw( + &Do_Abi_get_Key_0, + &Do_Abi_get_Value_1 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Key_0(IntPtr thisPtr, {{abiKeyType}}* __return_value__) + { + {{genericKeyType}} ____return_value__ = default; + *__return_value__ = default; + try + { + ____return_value__ = global::ABI.System.Collections.Generic.KeyValuePairMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_get_Key_0(thisPtr); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericKeyType, abiKeyType, keyTypeKind, "____return_value__")}}; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Value_1(IntPtr thisPtr, {{abiValueType}}* __return_value__) + { + {{genericValueType}} ____return_value__ = default; + *__return_value__ = default; + try + { + ____return_value__ = global::ABI.System.Collections.Generic.KeyValuePairMethods<{{genericKeyType}}, {{genericValueType}}>.Abi_get_Value_1(thisPtr); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericValueType, abiValueType, valueTypeKind, "____return_value__")}}; + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return keyValuePairInstantiation; + } + + // Delegates are special and initialize both the RCW and CCW. + private static string GetEventHandlerInstantiation(string genericType, string abiType, TypeKind typeKind) + { + string eventHandlerInstantiation = $$""" + internal static class EventHandler_{{GeneratorHelper.EscapeTypeNameForIdentifier(genericType)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + _ = global::ABI.System.EventHandlerMethods<{{genericType}}, {{abiType}}>.InitCcw( + &Do_Abi_Invoke + ); + _ = global::ABI.System.EventHandlerMethods<{{genericType}}, {{abiType}}>.InitRcwHelper( + &Invoke + ); + return true; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, {{abiType}} args) + { + try + { + global::ABI.System.EventHandlerMethods<{{genericType}}, {{abiType}}>.Abi_Invoke(thisPtr, MarshalInspectable.FromAbi(sender), {{GeneratorHelper.GetFromAbiMarshaler(genericType, abiType, typeKind, "args")}}); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + private static unsafe void Invoke(IObjectReference objRef, object sender, {{genericType}} args) + { + IntPtr ThisPtr = objRef.ThisPtr; + ObjectReferenceValue __sender = default; + {{GeneratorHelper.GetMarshalerDeclaration(genericType, abiType, typeKind, "args")}} + try + { + __sender = MarshalInspectable.CreateMarshaler2(sender); + IntPtr abiSender = MarshalInspectable.GetAbi(__sender); + {{GeneratorHelper.GetCreateMarshaler(genericType, abiType, typeKind, "args")}} + global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)ThisPtr)[3](ThisPtr, abiSender, {{GeneratorHelper.GetAbiFromMarshaler(genericType, abiType, typeKind, "args")}})); + global::System.GC.KeepAlive(objRef); + } + finally + { + MarshalInspectable.DisposeMarshaler(__sender); + {{GeneratorHelper.GetDisposeMarshaler(genericType, abiType, typeKind, "args")}} + } + } + } + """; + return eventHandlerInstantiation; + } + + private static string GetTypedEventHandlerInstantiation(EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.Windows.Foundation.TypedEventHandlerMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string typedEventHandlerInstantiation = $$""" + internal static class TypedEventHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + _ = {{staticMethodsClass}}.InitCcw( + &Do_Abi_Invoke + ); + _ = {{staticMethodsClass}}.InitRcwHelper( + &Invoke + ); + return true; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, {{genericParameters[0].AbiType}} sender, {{genericParameters[1].AbiType}} args) + { + try + { + {{staticMethodsClass}}.Abi_Invoke(thisPtr, {{GeneratorHelper.GetFromAbiMarshaler(genericParameters[0], "sender")}}, {{GeneratorHelper.GetFromAbiMarshaler(genericParameters[1], "args")}}); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + private static unsafe void Invoke(IObjectReference objRef, {{genericParameters[0].ProjectedType}} sender, {{genericParameters[1].ProjectedType}} args) + { + IntPtr ThisPtr = objRef.ThisPtr; + {{GeneratorHelper.GetMarshalerDeclaration(genericParameters[0], "sender")}} + {{GeneratorHelper.GetMarshalerDeclaration(genericParameters[1], "args")}} + try + { + {{GeneratorHelper.GetCreateMarshaler(genericParameters[0], "sender")}} + {{GeneratorHelper.GetCreateMarshaler(genericParameters[1], "args")}} + global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)ThisPtr)[3](ThisPtr, {{GeneratorHelper.GetAbiFromMarshaler(genericParameters[0], "sender")}}, {{GeneratorHelper.GetAbiFromMarshaler(genericParameters[1], "args")}})); + global::System.GC.KeepAlive(objRef); + } + finally + { + {{GeneratorHelper.GetDisposeMarshaler(genericParameters[0], "sender")}} + {{GeneratorHelper.GetDisposeMarshaler(genericParameters[1], "args")}} + } + } + } + """; + return typedEventHandlerInstantiation; + } + + private static string GetCompletedHandlerInstantiation(string completedHandler, string asyncInfoInterface, EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.{completedHandler}Methods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string interfaceWithGeneric = $"global::{asyncInfoInterface}<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; + string completedHandlerInstantiation = $$""" + internal static class {{completedHandler.Split('.')[^1]}}_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return {{staticMethodsClass}}.InitCcw( + &Do_Abi_Invoke + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr asyncInfo, global::Windows.Foundation.AsyncStatus asyncStatus) + { + try + { + {{staticMethodsClass}}.Abi_Invoke(thisPtr, MarshalInterface<{{interfaceWithGeneric}}>.FromAbi(asyncInfo), asyncStatus); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return completedHandlerInstantiation; + } + + private static string GetChangedHandlerInstantiation(string changedHandler, string senderInterface, string changedEventArgsInterface, EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.{changedHandler}Methods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string changedHandlerInstantiation = $$""" + internal static class {{changedHandler.Split('.')[^1]}}_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return {{staticMethodsClass}}.InitCcw( + &Do_Abi_Invoke + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr @event) + { + try + { + {{staticMethodsClass}}.Abi_Invoke(thisPtr, MarshalInterface<{{senderInterface}}>.FromAbi(sender), MarshalInterface<{{changedEventArgsInterface}}>.FromAbi(@event)); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return changedHandlerInstantiation; + } + + private static string GetProgressHandlerInstantiation(string progressHandler, string asyncInfoInterface, EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.{progressHandler}Methods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string asyncInfoInterfaceWithGeneric = $"global::{asyncInfoInterface}<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; + string asyncInfoInterfaceWithGenericMethodsClass = $"global::ABI.{asyncInfoInterface}Methods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; + var progressParameter = genericParameters.Last(); + string progressHandlerInstantiation = $$""" + internal static class {{progressHandler.Split('.')[^1]}}_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + _ = {{staticMethodsClass}}.InitCcw( + &Do_Abi_Invoke + ); + _ = {{staticMethodsClass}}.InitRcwHelper( + &Invoke + ); + return true; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr asyncInfo, {{progressParameter.AbiType}} progressInfo) + { + try + { + {{staticMethodsClass}}.Abi_Invoke(thisPtr, MarshalInterface<{{asyncInfoInterfaceWithGeneric}}>.FromAbi(asyncInfo), {{GeneratorHelper.GetFromAbiMarshaler(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}}); + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + private static unsafe void Invoke(IObjectReference objRef, {{asyncInfoInterfaceWithGeneric}} asyncInfo, {{progressParameter.ProjectedType}} progressInfo) + { + IntPtr ThisPtr = objRef.ThisPtr; + ObjectReferenceValue __asyncInfo = default; + {{GeneratorHelper.GetMarshalerDeclaration(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}} + try + { + __asyncInfo = MarshalInterface<{{asyncInfoInterfaceWithGeneric}}>.CreateMarshaler2(asyncInfo, {{asyncInfoInterfaceWithGenericMethodsClass}}.IID); + IntPtr abiAsyncInfo = MarshalInspectable.GetAbi(__asyncInfo); + {{GeneratorHelper.GetCreateMarshaler(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}} + global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)ThisPtr)[3](ThisPtr, abiAsyncInfo, {{GeneratorHelper.GetAbiFromMarshaler(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}})); + global::System.GC.KeepAlive(objRef); + } + finally + { + MarshalInterface<{{asyncInfoInterfaceWithGeneric}}>.DisposeMarshaler(__asyncInfo); + {{GeneratorHelper.GetDisposeMarshaler(progressParameter.ProjectedType, progressParameter.AbiType, progressParameter.TypeKind, "progressInfo")}} + } + } + } + """; + return progressHandlerInstantiation; + } + + private static string GetIAsyncActionWithProgressInstantiation(EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncActionWithProgressMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; + string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncActionWithProgressMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string instantiation = $$""" + internal static class IAsyncActionWithProgress_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return {{abiStaticMethodsClass}}.InitCcw( + &Do_Abi_put_Progress_0, + &Do_Abi_get_Progress_1, + &Do_Abi_put_Completed_2, + &Do_Abi_get_Completed_3, + &Do_Abi_GetResults_4 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetResults_4(IntPtr thisPtr) + { + try + { + {{staticMethodsClass}}.Do_Abi_GetResults_4(thisPtr); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_put_Progress_0(IntPtr thisPtr, IntPtr handler) + { + _ = AsyncActionProgressHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + try + { + {{staticMethodsClass}}.Do_Abi_put_Progress_0(thisPtr, global::ABI.Windows.Foundation.AsyncActionProgressHandler<{{genericParameters[0].ProjectedType}}>.FromAbi(handler)); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Progress_1(IntPtr thisPtr, IntPtr* __return_value__) + { + _ = AsyncActionProgressHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + global::Windows.Foundation.AsyncActionProgressHandler<{{genericParameters[0].ProjectedType}}> ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Progress_1(thisPtr); + *__return_value__ = global::ABI.Windows.Foundation.AsyncActionProgressHandler<{{genericParameters[0].ProjectedType}}>.FromManaged(____return_value__); + + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_put_Completed_2(IntPtr thisPtr, IntPtr handler) + { + _ = AsyncActionWithProgressCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + try + { + {{staticMethodsClass}}.Do_Abi_put_Completed_2(thisPtr, global::ABI.Windows.Foundation.AsyncActionWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}>.FromAbi(handler)); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Completed_3(IntPtr thisPtr, IntPtr* __return_value__) + { + _ = AsyncActionWithProgressCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + global::Windows.Foundation.AsyncActionWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}> ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Completed_3(thisPtr); + *__return_value__ = global::ABI.Windows.Foundation.AsyncActionWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}>.FromManaged(____return_value__); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return instantiation; + } + + private static string GetIAsyncOperationWithProgressInstantiation(EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncOperationWithProgressMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; + string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncOperationWithProgressMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string instantiation = $$""" + internal static class IAsyncOperationWithProgress_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return {{abiStaticMethodsClass}}.InitCcw( + &Do_Abi_put_Progress_0, + &Do_Abi_get_Progress_1, + &Do_Abi_put_Completed_2, + &Do_Abi_get_Completed_3, + &Do_Abi_GetResults_4 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetResults_4(IntPtr thisPtr, {{genericParameters[0].AbiType}}* __return_value__) + { + {{genericParameters[0].ProjectedType}} ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = {{staticMethodsClass}}.Do_Abi_GetResults_4(thisPtr); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericParameters[0], "____return_value__")}}; + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_put_Progress_0(IntPtr thisPtr, IntPtr handler) + { + _ = AsyncOperationProgressHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + try + { + {{staticMethodsClass}}.Do_Abi_put_Progress_0(thisPtr, global::ABI.Windows.Foundation.AsyncOperationProgressHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromAbi(handler)); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Progress_1(IntPtr thisPtr, IntPtr* __return_value__) + { + _ = AsyncOperationProgressHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + global::Windows.Foundation.AsyncOperationProgressHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}> ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Progress_1(thisPtr); + *__return_value__ = global::ABI.Windows.Foundation.AsyncOperationProgressHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromManaged(____return_value__); + + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_put_Completed_2(IntPtr thisPtr, IntPtr handler) + { + _ = AsyncOperationWithProgressCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + try + { + {{staticMethodsClass}}.Do_Abi_put_Completed_2(thisPtr, global::ABI.Windows.Foundation.AsyncOperationWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromAbi(handler)); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Completed_3(IntPtr thisPtr, IntPtr* __return_value__) + { + _ = AsyncOperationWithProgressCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + global::Windows.Foundation.AsyncOperationWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}> ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Completed_3(thisPtr); + *__return_value__ = global::ABI.Windows.Foundation.AsyncOperationWithProgressCompletedHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromManaged(____return_value__); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return instantiation; + } + + private static string GetIAsyncOperationInstantiation(EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncOperationMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; + string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.IAsyncOperationMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string instantiation = $$""" + internal static class IAsyncOperation_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return {{abiStaticMethodsClass}}.InitCcw( + &Do_Abi_put_Completed_0, + &Do_Abi_get_Completed_1, + &Do_Abi_GetResults_2 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_GetResults_2(IntPtr thisPtr, {{genericParameters[0].AbiType}}* __return_value__) + { + {{genericParameters[0].ProjectedType}} ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = {{staticMethodsClass}}.Do_Abi_GetResults_2(thisPtr); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericParameters[0], "____return_value__")}}; + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_put_Completed_0(IntPtr thisPtr, IntPtr handler) + { + _ = AsyncOperationCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + try + { + {{staticMethodsClass}}.Do_Abi_put_Completed_0(thisPtr, global::ABI.Windows.Foundation.AsyncOperationCompletedHandler<{{genericParameters[0].ProjectedType}}>.FromAbi(handler)); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Completed_1(IntPtr thisPtr, IntPtr* __return_value__) + { + _ = AsyncOperationCompletedHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + global::Windows.Foundation.AsyncOperationCompletedHandler<{{genericParameters[0].ProjectedType}}> ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Completed_1(thisPtr); + *__return_value__ = global::ABI.Windows.Foundation.AsyncOperationCompletedHandler<{{genericParameters[0].ProjectedType}}>.FromManaged(____return_value__); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return instantiation; + } + + private static string GetIMapChangedEventArgsInstantiation(EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IMapChangedEventArgsMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; + string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IMapChangedEventArgsMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string instantiation = $$""" + internal static class IMapChangedEventArgs_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return {{abiStaticMethodsClass}}.InitCcw( + &Do_Abi_get_CollectionChange_0, + &Do_Abi_get_Key_1 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_CollectionChange_0(IntPtr thisPtr, global::Windows.Foundation.Collections.CollectionChange* __return_value__) + { + *__return_value__ = default; + + try + { + *__return_value__ = {{staticMethodsClass}}.Do_Abi_get_CollectionChange_0(thisPtr); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_get_Key_1(IntPtr thisPtr, {{genericParameters[0].AbiType}}* __return_value__) + { + {{genericParameters[0].ProjectedType}} ____return_value__ = default; + + *__return_value__ = default; + + try + { + ____return_value__ = {{staticMethodsClass}}.Do_Abi_get_Key_1(thisPtr); + *__return_value__ = {{GeneratorHelper.GetFromManagedMarshaler(genericParameters[0], "____return_value__")}}; + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return instantiation; + } + + private static string GetIObservableMapInstantiation(EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IObservableMapMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; + string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IObservableMapMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string instantiation = $$""" + internal static class IObservableMap_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return {{abiStaticMethodsClass}}.InitCcw( + &Do_Abi_add_MapChanged_0, + &Do_Abi_remove_MapChanged_1 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_add_MapChanged_0(IntPtr thisPtr, IntPtr vhnd, global::WinRT.EventRegistrationToken* __return_value__) + { + *__return_value__ = default; + _ = MapChangedEventHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + try + { + *__return_value__ = {{staticMethodsClass}}.Do_Abi_add_MapChanged_0(thisPtr, global::ABI.Windows.Foundation.Collections.MapChangedEventHandler<{{genericParameters[0].ProjectedType}}, {{genericParameters[1].ProjectedType}}>.FromAbi(vhnd)); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_remove_MapChanged_1(IntPtr thisPtr, global::WinRT.EventRegistrationToken token) + { + try + { + {{staticMethodsClass}}.Do_Abi_remove_MapChanged_1(thisPtr, token); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return instantiation; + } + + private static string GetIObservableVectorInstantiation(EquatableArray genericParameters) + { + string staticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IObservableVectorMethods<{GetGenericParametersAsString(genericParameters, ", ", false, false)}>"; + string abiStaticMethodsClass = $"global::ABI.Windows.Foundation.Collections.IObservableVectorMethods<{GetGenericParametersAsString(genericParameters, ", ", true, false)}>"; + string instantiation = $$""" + internal static class IObservableVector_{{GetGenericParametersAsString(genericParameters, "_", false)}} + { + private static readonly bool _initialized = Init(); + internal static bool Initialized => _initialized; + + private static unsafe bool Init() + { + return {{abiStaticMethodsClass}}.InitCcw( + &Do_Abi_add_VectorChanged_0, + &Do_Abi_remove_VectorChanged_1 + ); + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_add_VectorChanged_0(IntPtr thisPtr, IntPtr vhnd, global::WinRT.EventRegistrationToken* __return_value__) + { + *__return_value__ = default; + _ = VectorChangedEventHandler_{{GetGenericParametersAsString(genericParameters, "_", false)}}.Initialized; + try + { + *__return_value__ = {{staticMethodsClass}}.Do_Abi_add_VectorChanged_0(thisPtr, global::ABI.Windows.Foundation.Collections.VectorChangedEventHandler<{{genericParameters[0].ProjectedType}}>.FromAbi(vhnd)); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] + private static unsafe int Do_Abi_remove_VectorChanged_1(IntPtr thisPtr, global::WinRT.EventRegistrationToken token) + { + try + { + {{staticMethodsClass}}.Do_Abi_remove_VectorChanged_1(thisPtr, token); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + """; + return instantiation; + } + + private static string GetGenericParametersAsString(EquatableArray genericParameters, string separator, bool includeAbiTypes, bool escape = true) + { + string genericParametersStr = string.Join(separator, + genericParameters.Select(genericParameter => + { + if (includeAbiTypes) + { + return string.Join( + separator, + escape ? GeneratorHelper.EscapeTypeNameForIdentifier(genericParameter.ProjectedType) : genericParameter.ProjectedType, + escape ? GeneratorHelper.EscapeTypeNameForIdentifier(genericParameter.AbiType) : genericParameter.AbiType); + } + else + { + return escape ? GeneratorHelper.EscapeTypeNameForIdentifier(genericParameter.ProjectedType) : genericParameter.ProjectedType; + } + })); + return genericParametersStr; + } + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/Helper.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Helper.cs similarity index 97% rename from src/Authoring/WinRT.SourceGenerator/Helper.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/Helper.cs index 83f5e67cf..06b77a72f 100644 --- a/src/Authoring/WinRT.SourceGenerator/Helper.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Helper.cs @@ -1,1252 +1,1252 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; - -namespace Generator -{ - public static class Helper - { - public static Guid EncodeGuid(byte[] data) - { - if (BitConverter.IsLittleEndian) - { - // swap bytes of int a - byte t = data[0]; - data[0] = data[3]; - data[3] = t; - t = data[1]; - data[1] = data[2]; - data[2] = t; - // swap bytes of short b - t = data[4]; - data[4] = data[5]; - data[5] = t; - // swap bytes of short c and encode rfc time/version field - t = data[6]; - data[6] = data[7]; - data[7] = (byte)((t & 0x0f) | (5 << 4)); - // encode rfc clock/reserved field - data[8] = (byte)((data[8] & 0x3f) | 0x80); - } - return new Guid(data.Take(16).ToArray()); - } - } - - class AttributeDataComparer : IEqualityComparer - { - public bool Equals(AttributeData x, AttributeData y) - { - return string.CompareOrdinal(x.ToString(), y.ToString()) == 0; - } - - public int GetHashCode(AttributeData obj) - { - return obj.ToString().GetHashCode(); - } - } - - static class GeneratorExecutionContextHelper - { - public static string GetAssemblyName(this GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyName", out var assemblyName); - return assemblyName; - } - - public static string GetAssemblyVersion(this GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyVersion", out var assemblyVersion); - return assemblyVersion; - } - - [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "We need to do file IO to invoke the 'cswinrt' tool.")] - public static string GetGeneratedFilesDir(this GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTGeneratedFilesDir", out var generatedFilesDir); - Directory.CreateDirectory(generatedFilesDir); - return generatedFilesDir; - } - - public static string GetCsWinRTExeTFM(this GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTExeTFM", out var csWinRTExeTFM); - return csWinRTExeTFM; - } - - public static bool IsCsWinRTComponent(this GeneratorExecutionContext context) - { - if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTComponent", out var isCsWinRTComponentStr)) - { - return bool.TryParse(isCsWinRTComponentStr, out var isCsWinRTComponent) && isCsWinRTComponent; - } - - return false; - } - - public static bool IsCsWinRTComponent(this AnalyzerConfigOptionsProvider provider) - { - if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTComponent", out var isCsWinRTComponentStr)) - { - return bool.TryParse(isCsWinRTComponentStr, out var isCsWinRTComponent) && isCsWinRTComponent; - } - - return false; - } - - public static bool IsCsWinRTAotOptimizerEnabled(this AnalyzerConfigOptionsProvider provider) - { - if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTAotOptimizerEnabled", out var isCsWinRTAotOptimizerEnabledStr)) - { - return (bool.TryParse(isCsWinRTAotOptimizerEnabledStr, out var isCsWinRTAotOptimizerEnabled) && isCsWinRTAotOptimizerEnabled) || - string.Equals(isCsWinRTAotOptimizerEnabledStr, "OptIn", StringComparison.OrdinalIgnoreCase) || - string.Equals(isCsWinRTAotOptimizerEnabledStr, "Auto", StringComparison.OrdinalIgnoreCase); - } - - return false; - } - - private enum CsWinRTAotOptimizerMode - { - Disabled = 0, - OptIn = 1, - Auto = 2, - Default = 3, - } - - public static bool IsCsWinRTAotOptimizerInAutoMode(AnalyzerConfigOptionsProvider provider, Compilation compilation) - { - var mode = GetMode(provider); - - if (mode == CsWinRTAotOptimizerMode.Default) - { - // If mode is default and this is a WinUI or UWP project, which we detect by using the Button type as a marker, - // then AOT optimizer is running in auto mode because in both projects the main API boundary is WinRT. - // For CsWinRT components, we also run by default in auto mode. - return provider.IsCsWinRTComponent() || - compilation.GetTypeByMetadataName("Microsoft.UI.Xaml.Controls.Button") is not null || - compilation.GetTypeByMetadataName("Windows.UI.Xaml.Controls.Button") is not null || - // If warning level was explicitly set to 2 without a mode set, - // we don't want to change the behavior of those projects who were - // relying on it running. If they set the mode, then the mode would - // be respected. - provider.GetCsWinRTAotWarningLevel() == 2; - } - - // If mode is not the default, check if it is set explicitly to Auto. - return mode == CsWinRTAotOptimizerMode.Auto; - - static CsWinRTAotOptimizerMode GetMode(AnalyzerConfigOptionsProvider provider) - { - if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTAotOptimizerEnabled", out var isCsWinRTAotOptimizerEnabledStr)) - { - if (string.Equals(isCsWinRTAotOptimizerEnabledStr, "OptIn", StringComparison.OrdinalIgnoreCase)) - { - return CsWinRTAotOptimizerMode.OptIn; - } - - if (string.Equals(isCsWinRTAotOptimizerEnabledStr, "Auto", StringComparison.OrdinalIgnoreCase)) - { - return CsWinRTAotOptimizerMode.Auto; - } - - if (bool.TryParse(isCsWinRTAotOptimizerEnabledStr, out var isCsWinRTAotOptimizerEnabled) && isCsWinRTAotOptimizerEnabled) - { - return CsWinRTAotOptimizerMode.Default; - } - } - - return CsWinRTAotOptimizerMode.Disabled; - } - } - - public static bool GetCsWinRTRcwFactoryFallbackGeneratorForceOptIn(this AnalyzerConfigOptionsProvider provider) - { - if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTRcwFactoryFallbackGeneratorForceOptIn", out var csWinRTRcwFactoryFallbackGeneratorForceOptIn)) - { - return bool.TryParse(csWinRTRcwFactoryFallbackGeneratorForceOptIn, out var isCsWinRTRcwFactoryFallbackGeneratorForceOptIn) && isCsWinRTRcwFactoryFallbackGeneratorForceOptIn; - } - - return false; - } - - public static bool GetCsWinRTMergeReferencedActivationFactories(this AnalyzerConfigOptionsProvider provider) - { - if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTMergeReferencedActivationFactories", out var csWinRTMergeReferencedActivationFactories)) - { - return bool.TryParse(csWinRTMergeReferencedActivationFactories, out var isCsWinRTMergeReferencedActivationFactories) && isCsWinRTMergeReferencedActivationFactories; - } - - return false; - } - - public static bool GetCsWinRTRcwFactoryFallbackGeneratorForceOptOut(this AnalyzerConfigOptionsProvider provider) - { - if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTRcwFactoryFallbackGeneratorForceOptOut", out var csWinRTRcwFactoryFallbackGeneratorForceOptOut)) - { - return bool.TryParse(csWinRTRcwFactoryFallbackGeneratorForceOptOut, out var isCsWinRTRcwFactoryFallbackGeneratorForceOptOut) && isCsWinRTRcwFactoryFallbackGeneratorForceOptOut; - } - - return false; - } - - public static bool IsCsWinRTCcwLookupTableGeneratorEnabled(this AnalyzerConfigOptionsProvider provider) - { - if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTCcwLookupTableGeneratorEnabled", out var csWinRTCcwLookupTableGeneratorEnabled)) - { - return bool.TryParse(csWinRTCcwLookupTableGeneratorEnabled, out var isCsWinRTCcwLookupTableGeneratorEnabled) && isCsWinRTCcwLookupTableGeneratorEnabled; - } - - return false; - } - - public static bool GetCsWinRTUseWindowsUIXamlProjections(this AnalyzerConfigOptionsProvider provider) - { - if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTUseWindowsUIXamlProjections", out var csWinRTUseWindowsUIXamlProjections)) - { - return bool.TryParse(csWinRTUseWindowsUIXamlProjections, out var isCsWinRTUseWindowsUIXamlProjectionsEnabled) && isCsWinRTUseWindowsUIXamlProjectionsEnabled; - } - - return false; - } - - public static int GetCsWinRTAotWarningLevel(this AnalyzerConfigOptionsProvider provider) - { - if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTAotWarningLevel", out var csWinRTAotWarningLevelStr) && - int.TryParse(csWinRTAotWarningLevelStr, out var csWinRTAotWarningLevel)) - { - return csWinRTAotWarningLevel; - } - - return 0; - } - - public static bool ShouldGenerateWinMDOnly(this GeneratorExecutionContext context) - { - if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTGenerateWinMDOnly", out var CsWinRTGenerateWinMDOnlyStr)) - { - return bool.TryParse(CsWinRTGenerateWinMDOnlyStr, out var CsWinRTGenerateWinMDOnly) && CsWinRTGenerateWinMDOnly; - } - - return false; - } - - /// - /// Gets whether the "CsWinRTAotExportsEnabled" MSBuild property is defined. - /// - /// The input value to use. - /// Whether the "CsWinRTAotExportsEnabled" MSBuild property is defined. - public static bool ShouldGenerateWinRTNativeExports(this GeneratorExecutionContext context) - { - if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTAotExportsEnabled", out var isCsWinRTAotExportsEnabledStr)) - { - return bool.TryParse(isCsWinRTAotExportsEnabledStr, out var isCsWinRTAotExportsEnabled) && isCsWinRTAotExportsEnabled; - } - - return false; - } - - public static string GetCsWinRTExe(this GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTExe", out var cswinrtExe); - return cswinrtExe; - } - - public static bool GetKeepGeneratedSources(this GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTKeepGeneratedSources", out var keepGeneratedSourcesStr); - return keepGeneratedSourcesStr != null && bool.TryParse(keepGeneratedSourcesStr, out var keepGeneratedSources) && keepGeneratedSources; - } - - public static string GetCsWinRTWindowsMetadata(this GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTWindowsMetadata", out var cswinrtWindowsMetadata); - return cswinrtWindowsMetadata; - } - - public static string GetCsWinRTDependentMetadata(this GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTAuthoringInputs", out var winmds); - return winmds; - } - - public static string GetWinmdOutputFile(this GeneratorExecutionContext context) - { - var fileName = context.GetAssemblyName(); - if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTWinMDOutputFile", out var ret)) - { - fileName = ret!; - } - return Path.Combine(context.GetGeneratedFilesDir(), fileName + ".winmd"); - } - - public static bool GetCsWinRTMergeReferencedActivationFactories(this GeneratorExecutionContext context) - { - if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTMergeReferencedActivationFactories", out var csWinRTMergeReferencedActivationFactories)) - { - return bool.TryParse(csWinRTMergeReferencedActivationFactories, out var isCsWinRTMergeReferencedActivationFactories) && isCsWinRTMergeReferencedActivationFactories; - } - - return false; - } - } - - static class GeneratorHelper - { - private static bool IsFundamentalType(ISymbol type) - { - if (type is INamedTypeSymbol namedTypeSymbol) - { - switch (namedTypeSymbol.SpecialType) - { - case SpecialType.System_Boolean: - case SpecialType.System_String: - case SpecialType.System_Single: - case SpecialType.System_Double: - case SpecialType.System_UInt16: - case SpecialType.System_UInt32: - case SpecialType.System_UInt64: - case SpecialType.System_Int16: - case SpecialType.System_Int32: - case SpecialType.System_Int64: - case SpecialType.System_Char: - case SpecialType.System_Byte: - case SpecialType.System_Object: - return true; - } - } - - return type.ToDisplayString() == "System.Guid"; - } - - /// - /// Checks whether an assembly contains old projections. - /// - /// The assembly to inspect. - /// Whether contains old projections. - public static bool IsOldProjectionAssembly(IAssemblySymbol assemblySymbol) - { - // We only care about assemblies that have some dependent assemblies - if (assemblySymbol.Modules.First() is not { ReferencedAssemblies: { Length: > 0 } dependentAssemblies }) - { - return false; - } - - // Scan all dependent assemblies to look for CsWinRT with version < 2.0.8 - foreach (AssemblyIdentity assemblyIdentity in dependentAssemblies) - { - if (assemblyIdentity.Name == "WinRT.Runtime") - { - return assemblyIdentity.Version < new Version(2, 0, 8) && - assemblyIdentity.Version != new Version(0, 0, 0, 0); - } - } - - // This assembly is not a projection assembly - return false; - } - - public static bool IsOldCsWinRTExe(GeneratorExecutionContext context) - { - string cswinrtExe = context.GetCsWinRTExe(); - var cswinrtExeVersion = new Version(FileVersionInfo.GetVersionInfo(cswinrtExe).FileVersion); - return cswinrtExeVersion < new Version(2, 1, 0) && cswinrtExeVersion != new Version(0, 0, 0, 0); - } - - public static bool AllowUnsafe(Compilation compilation) - { - return compilation is CSharpCompilation csharpCompilation && csharpCompilation.Options.AllowUnsafe; - } - - // Returns whether it is a WinRT class or interface. - // If the bool parameter is true, then custom mapped interfaces are also considered. - // This function is similar to whether it is a WinRT type, but custom type mapped - // classes are excluded given those are C# implemented classes such as string. - public static Func IsWinRTClassOrInterface(Compilation compilation, Func isWinRTType, TypeMapper mapper) - { - var winrtRuntimeTypeAttribute = compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute"); - return IsWinRTClassOrInterfaceHelper; - - bool IsWinRTClassOrInterfaceHelper(ISymbol type, bool includeMappedInterfaces) - { - if (type is ITypeSymbol typeSymbol && typeSymbol.TypeKind == TypeKind.Interface) - { - return isWinRTType(type, mapper); - } - - return HasAttributeWithType(type, winrtRuntimeTypeAttribute); - } - } - - public static bool IsWinRTType(ISymbol type, TypeMapper mapper) - { - return IsWinRTType(type, null, mapper); - } - - public static bool IsWinRTType(ISymbol type, Func isAuthoringWinRTType, TypeMapper mapper) - { - bool isProjectedType = type.GetAttributes(). - Any(static attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeTypeAttribute") == 0) || - IsFundamentalType(type); - - if (!isProjectedType & type.ContainingNamespace != null) - { - isProjectedType = mapper.HasMappingForType(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); - } - - // Ensure all generic parameters are WinRT types. - if (isProjectedType && type is INamedTypeSymbol namedType && namedType.IsGenericType && !namedType.IsDefinition) - { - isProjectedType = namedType.TypeArguments.All(t => - IsWinRTType(t, isAuthoringWinRTType, mapper) || - (isAuthoringWinRTType != null && isAuthoringWinRTType(t, mapper))); - } - - return isProjectedType; - } - - public static bool IsWinRTType(ISymbol type, ITypeSymbol winrtRuntimeTypeAttribute, TypeMapper mapper, bool isComponentProject, IAssemblySymbol currentAssembly) - { - if (IsFundamentalType(type)) - { - return true; - } - - if (isComponentProject && - // Make sure type is in component project. - SymbolEqualityComparer.Default.Equals(type.ContainingAssembly, currentAssembly) && - type.DeclaredAccessibility == Accessibility.Public) - { - // Authoring diagnostics will make sure all public types are valid WinRT types. - return true; - } - - bool isProjectedType = HasAttributeWithType(type, winrtRuntimeTypeAttribute); - if (!isProjectedType & type.ContainingNamespace != null) - { - isProjectedType = mapper.HasMappingForType(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); - } - - // Ensure all generic parameters are WinRT types. - if (isProjectedType && - type is INamedTypeSymbol namedType && - namedType.IsGenericType && - !namedType.IsDefinition) - { - isProjectedType = namedType.TypeArguments.All(t => IsWinRTType(t, winrtRuntimeTypeAttribute, mapper, isComponentProject, currentAssembly)); - } - - return isProjectedType; - } - - public static bool IsWinRTTypeOrImplementsWinRTType(ISymbol type, ITypeSymbol winrtRuntimeTypeAttribute, TypeMapper mapper, bool isComponentProject, IAssemblySymbol currentAssembly) - { - if (IsWinRTType(type, winrtRuntimeTypeAttribute, mapper, isComponentProject, currentAssembly)) - { - return true; - } - - if (type is INamedTypeSymbol namedType && - namedType.AllInterfaces.Any(iface => IsWinRTType(iface, winrtRuntimeTypeAttribute, mapper, isComponentProject, currentAssembly))) - { - return true; - } - - return false; - } - - // Assuming a type is a WinRT type, this determines whether it is a WinRT type from custom type mappings. - // i.e Whether it is a built-in type that is also a WinRT type. - public static bool IsCustomMappedType(ISymbol type, TypeMapper mapper) - { - if (IsFundamentalType(type)) - { - return true; - } - - bool isCustomMappedType = false; - if (type.ContainingNamespace != null) - { - isCustomMappedType = mapper.HasMappingForType(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); - } - - // Ensure all generic parameters are WinRT types. - if (isCustomMappedType && - type is INamedTypeSymbol namedType && - namedType.IsGenericType && - !namedType.IsDefinition) - { - isCustomMappedType = namedType.TypeArguments.All(t => IsCustomMappedType(t, mapper)); - } - - return isCustomMappedType; - } - - // Checks if the interface references any internal types (either the interface itself or within its generic types). - public static bool IsInternalInterfaceFromReferences(INamedTypeSymbol iface, IAssemblySymbol currentAssembly) - { - if (iface.DeclaredAccessibility == Accessibility.Internal && - !SymbolEqualityComparer.Default.Equals(iface.ContainingAssembly, currentAssembly)) - { - return true; - } - - if (iface.IsGenericType) - { - // Making use of HashSet to avoid checking multiple times for same type and to avoid doing recursive calls. - HashSet genericArgumentsToProcess = new(iface.TypeArguments, SymbolEqualityComparer.Default); - HashSet visitedTypes = new(SymbolEqualityComparer.Default); - while (genericArgumentsToProcess.Count != 0) - { - var currentType = genericArgumentsToProcess.First(); - visitedTypes.Add(currentType); - genericArgumentsToProcess.Remove(currentType); - - if (currentType.DeclaredAccessibility == Accessibility.Internal && - !SymbolEqualityComparer.Default.Equals(currentType.ContainingAssembly, currentAssembly)) - { - return true; - } - - if (currentType is INamedTypeSymbol currentNamedTypeSymbol) - { - if (currentNamedTypeSymbol.IsGenericType) - { - foreach (var typeArgument in currentNamedTypeSymbol.TypeArguments) - { - if (!visitedTypes.Contains(typeArgument)) - { - genericArgumentsToProcess.Add(typeArgument); - } - } - } - } - } - } - - return false; - } - - // Checks whether the symbol references any generic that hasn't been instantiated - // and is used by a WinRT interface. For instance, List where T is a generic. - // If the generic isn't used by any WinRT interface, this returns false as for - // instance, we can still generate the vtable attribute for it. - public static bool HasNonInstantiatedWinRTGeneric(ITypeSymbol symbol, TypeMapper mapper) - { - return symbol is INamedTypeSymbol namedType && - (IsArgumentTypeParameter(namedType) || - (namedType.TypeArguments.Any(IsArgumentTypeParameter) && - namedType.AllInterfaces.Any(iface => iface.TypeArguments.Any(IsArgumentTypeParameter) && - // Checks if without the non-instantiated generic, whether it would be a WinRT type. - IsWinRTType(iface.OriginalDefinition, null, mapper)))); - - static bool IsArgumentTypeParameter(ITypeSymbol argument) - { - return argument.TypeKind == TypeKind.TypeParameter; - } - } - - public static bool IsPartial(INamedTypeSymbol symbol) - { - bool isPartial = true; - for (ITypeSymbol parent = symbol; parent is not null; parent = parent.ContainingType) - { - isPartial &= parent.DeclaringSyntaxReferences.Any( - static syntax => syntax.GetSyntax() is BaseTypeDeclarationSyntax declaration && - declaration.Modifiers.Any(SyntaxKind.PartialKeyword)); - } - return isPartial; - } - - public static bool IsPartial(TypeDeclarationSyntax node) - { - bool isPartial = true; - for (TypeDeclarationSyntax parent = node; parent is not null; parent = parent.Parent as TypeDeclarationSyntax) - { - isPartial &= parent.Modifiers.Any(static m => m.IsKind(SyntaxKind.PartialKeyword)); - } - return isPartial; - } - - public static bool HasPrivateclass(ITypeSymbol symbol) - { - return symbol is INamedTypeSymbol namedType && - (namedType.DeclaredAccessibility == Accessibility.Private || - namedType.TypeArguments.Any(static argument => argument.DeclaredAccessibility == Accessibility.Private)); - } - - public static bool HasWinRTExposedTypeAttribute(ISymbol type) - { - return type.GetAttributes(). - Any(static attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WinRTExposedTypeAttribute") == 0); - } - - public static bool HasWinRTRuntimeClassNameAttribute(ISymbol type, Compilation compilation) - { - var winrtRuntimeClassNameAttribute = compilation.GetTypeByMetadataName("WinRT.WinRTRuntimeClassNameAttribute"); - if (winrtRuntimeClassNameAttribute is null) - { - return false; - } - - return HasAttributeWithType(type, winrtRuntimeClassNameAttribute); - } - - public static bool IsWinRTType(MemberDeclarationSyntax node) - { - bool isProjectedType = node.AttributeLists.SelectMany(static list => list.Attributes). - Any(static attribute => string.CompareOrdinal(attribute.Name.NormalizeWhitespace().ToFullString(), "global::WinRT.WindowsRuntimeType") == 0); - return isProjectedType; - } - - public static bool HasBindableCustomPropertyAttribute(MemberDeclarationSyntax node) - { - return node.AttributeLists.SelectMany(static list => list.Attributes).Any(IsBindableCustomPropertyAttribute); - - // Check based on identifier name if this is the GeneratedBindableCustomProperty attribute. - // Technically this can be a different namespace, but we will confirm later once - // we have access to the semantic model. - static bool IsBindableCustomPropertyAttribute(AttributeSyntax attribute) - { - var nameSyntax = attribute.Name; - if (nameSyntax is QualifiedNameSyntax qualifiedName) - { - // Right would have the attribute while left is the namespace. - nameSyntax = qualifiedName.Right; - } - - return nameSyntax is IdentifierNameSyntax name && - (name.Identifier.ValueText == "GeneratedBindableCustomProperty" || - name.Identifier.ValueText == "GeneratedBindableCustomPropertyAttribute"); - } - } - - /// - /// Checks whether or not a given symbol has an attribute with the specified type. - /// - /// The input instance to check. - /// The instance for the attribute type to look for. - /// Whether or not has an attribute with the specified type. - public static bool HasAttributeWithType(ISymbol symbol, ITypeSymbol attributeTypeSymbol) - { - foreach (AttributeData attribute in symbol.GetAttributes()) - { - if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, attributeTypeSymbol)) - { - return true; - } - } - - return false; - } - - /// - /// Checks whether a symbol is annotated with [WinRTExposedType(typeof(WinRTManagedOnlyTypeDetails))]. - /// - public static bool IsManagedOnlyType(ISymbol symbol, ITypeSymbol winrtExposedTypeAttribute, ITypeSymbol winrtManagedOnlyTypeDetails) - { - foreach (AttributeData attribute in symbol.GetAttributes()) - { - if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, winrtExposedTypeAttribute)) - { - if (attribute.ConstructorArguments is [{ Kind: TypedConstantKind.Type, Type: ITypeSymbol exposedTypeDetails }] && - SymbolEqualityComparer.Default.Equals(exposedTypeDetails, winrtManagedOnlyTypeDetails)) - { - return true; - } - - // A type can have just one [WinRTExposedType] attribute. If the details are not WinRTManagedOnlyTypeDetails, - // we can immediatley stop here and avoid checking all remaining attributes, as we couldn't possibly match. - return false; - } - } - - return false; - } - - public static Func IsWinRTType(Compilation compilation, bool isComponentProject) - { - var winrtTypeAttribute = compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute"); - return IsWinRTTypeHelper; - - bool IsWinRTTypeHelper(ISymbol type, TypeMapper typeMapper) - { - return IsWinRTType(type, winrtTypeAttribute, typeMapper, isComponentProject, compilation.Assembly); - } - } - - public static Func IsManagedOnlyType(Compilation compilation) - { - var winrtExposedTypeAttribute = compilation.GetTypeByMetadataName("WinRT.WinRTExposedTypeAttribute"); - var winrtManagedOnlyTypeDetails = compilation.GetTypeByMetadataName("WinRT.WinRTManagedOnlyTypeDetails"); - - return IsManagedOnlyTypeHelper; - - bool IsManagedOnlyTypeHelper(ISymbol type) - { - return IsManagedOnlyType(type, winrtExposedTypeAttribute, winrtManagedOnlyTypeDetails); - } - } - - private static string GetAbiTypeForFundamentalType(ISymbol type) - { - if (type is INamedTypeSymbol namedTypeSymbol) - { - switch (namedTypeSymbol.SpecialType) - { - case SpecialType.System_Boolean: - return "byte"; - case SpecialType.System_String: - return "IntPtr"; - case SpecialType.System_Char: - return "ushort"; - case SpecialType.System_Object: - return "IntPtr"; - case SpecialType.System_Single: - case SpecialType.System_Double: - case SpecialType.System_UInt16: - case SpecialType.System_UInt32: - case SpecialType.System_UInt64: - case SpecialType.System_Int16: - case SpecialType.System_Int32: - case SpecialType.System_Int64: - case SpecialType.System_Byte: - return type.ToDisplayString(); - } - } - - return type.ToDisplayString(); - } - - public static bool IsBlittableValueType(ITypeSymbol type, TypeMapper typeMapper) - { - if (!type.IsValueType) - { - return false; - } - - if (type.SpecialType != SpecialType.None) - { - switch (type.SpecialType) - { - case SpecialType.System_Single: - case SpecialType.System_Double: - case SpecialType.System_UInt16: - case SpecialType.System_UInt32: - case SpecialType.System_UInt64: - case SpecialType.System_Int16: - case SpecialType.System_Int32: - case SpecialType.System_Int64: - case SpecialType.System_Byte: - case SpecialType.System_SByte: - case SpecialType.System_IntPtr: - case SpecialType.System_UIntPtr: - return true; - default: - return false; - } - } - - if (type.ContainingNamespace != null) - { - string customTypeMapKey = string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName); - if (typeMapper.HasMappingForType(customTypeMapKey)) - { - return typeMapper.GetMappedType(customTypeMapKey).IsBlittable(); - } - } - - if (type.TypeKind == TypeKind.Enum) - { - return true; - } - - if (type.TypeKind == TypeKind.Struct) - { - foreach (var typeMember in type.GetMembers()) - { - if (typeMember is IFieldSymbol field && - !field.IsStatic && - !IsBlittableValueType(field.Type, typeMapper)) - { - return false; - } - } - } - return true; - } - - public static string GetAbiType(ITypeSymbol type, TypeMapper mapper) - { - if (IsFundamentalType(type)) - { - return GetAbiTypeForFundamentalType(type); - } - - var typeStr = type.ToDisplayString(); - if (typeStr == "System.Type") - { - return "ABI.System.Type"; - } - else if (typeStr.StartsWith("System.Collections.Generic.KeyValuePair<")) - { - return "IntPtr"; - } - else if (typeStr == "System.Exception") - { - return "ABI.System.Exception"; - } - - if (type.IsValueType && !type.NullableAnnotation.HasFlag(NullableAnnotation.Annotated)) - { - string customTypeMapKey = string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName); - if (mapper.HasMappingForType(customTypeMapKey)) - { - string prefix = mapper.GetMappedType(customTypeMapKey).IsBlittable() ? "" : "ABI."; - return prefix + typeStr; - } - - if (!IsBlittableValueType(type, mapper)) - { - var winrtHelperAttribute = type.GetAttributes(). - Where(static attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeHelperTypeAttribute") == 0). - FirstOrDefault(); - if (winrtHelperAttribute != null && - winrtHelperAttribute.ConstructorArguments.Any()) - { - return winrtHelperAttribute.ConstructorArguments[0].Value.ToString(); - } - // Handling authoring scenario where Impl type has the attributes and - // if the current component is the one being authored, it may not be - // generated yet to check given it is the same compilation. - else - { - return "ABI." + typeStr; - } - } - else - { - return typeStr; - } - } - - return "IntPtr"; - } - - public static string GetMarshalerClass(string type, string abiType, TypeKind kind, bool isArray, bool useGenericMarshaler = false) - { - if (type == "System.String" || type == "string") - { - return "MarshalString"; - } - else if (type == "System.Type" || type == "Type") - { - if (isArray) - { - return "MarshalNonBlittable"; - } - else - { - return "global::ABI.System.Type"; - } - } - else if (type == "System.Exception" || type == "Exception") - { - if (isArray) - { - return "MarshalNonBlittable"; - } - else - { - return "global::ABI.System.Exception"; - } - } - else if (type == "System.Object" || type == "object") - { - return "MarshalInspectable"; - } - else if (type.StartsWith("System.Collections.Generic.KeyValuePair<")) - { - return $$"""MarshalInterface<{{type}}>"""; - } - else if (kind == TypeKind.Enum) - { - if (isArray) - { - return $$"""MarshalBlittable<{{type}}>"""; - } - else - { - return ""; - } - } - else if (kind == TypeKind.Struct) - { - if (type == abiType) - { - if (isArray) - { - return $$"""MarshalBlittable<{{type}}>"""; - } - else - { - return ""; - } - } - else - { - if (isArray) - { - return $$"""MarshalNonBlittable<{{type}}>"""; - } - else - { - return "global::ABI." + type; - } - } - } - else if (kind == TypeKind.Interface) - { - return $$"""MarshalInterface<{{type}}>"""; - } - else if (kind == TypeKind.Class || kind == TypeKind.Delegate) - { - return useGenericMarshaler ? "MarshalInspectable" : "global::ABI." + type; - } - - throw new ArgumentException(); - } - - public static string GetFromAbiMarshaler(GenericParameter genericParameter, string arg) - { - return GetFromAbiMarshaler( - genericParameter.ProjectedType, - genericParameter.AbiType, - genericParameter.TypeKind, - arg); - } - - public static string GetFromAbiMarshaler(string type, string abiType, TypeKind kind, string arg) - { - string marshalerType = GetMarshalerClass(type, abiType, kind, false); - if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType)) - { - return arg; - } - else if (type == "bool") - { - return $$"""({{arg}} != 0)"""; - } - else if (type == "char") - { - return $$"""(char){{arg}}"""; - } - else - { - return $$"""{{marshalerType}}.FromAbi({{arg}})"""; - } - } - - public static string GetFromManagedMarshaler(GenericParameter genericParameter, string arg) - { - return GetFromManagedMarshaler( - genericParameter.ProjectedType, - genericParameter.AbiType, - genericParameter.TypeKind, - arg); - } - - public static string GetFromManagedMarshaler(string type, string abiType, TypeKind kind, string arg) - { - string marshalerType = GetMarshalerClass(type, abiType, kind, false); - if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType)) - { - return arg; - } - else if (type == "bool") - { - return $$"""(byte)({{arg}} ? 1 : 0)"""; - } - else if (type == "char") - { - return $$"""(ushort){{arg}}"""; - } - else - { - return $$"""{{marshalerType}}.FromManaged({{arg}})"""; - } - } - - public static string GetCopyManagedArrayMarshaler(string type, string abiType, TypeKind kind) - { - if (kind == TypeKind.Class || kind == TypeKind.Delegate) - { - // TODO: Classes and delegates are missing CopyManagedArray. - return $$"""Marshaler<{{type}}>"""; - } - else - { - return GetMarshalerClass(type, abiType, kind, true); - } - } - - public static string GetCreateMarshaler(GenericParameter genericParameter, string arg) - { - return GetCreateMarshaler( - genericParameter.ProjectedType, - genericParameter.AbiType, - genericParameter.TypeKind, - arg); - } - - public static string GetCreateMarshaler(string type, string abiType, TypeKind kind, string arg) - { - if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType) || - type == "bool" || - type == "char") - { - return ""; - } - else if (type == "System.String" || type == "string") - { - // TODO: Consider switching to pinning - return $$"""__{{arg}} = MarshalString.CreateMarshaler({{arg}});"""; - } - else if (kind == TypeKind.Struct) - { - string marshalerClass = GetMarshalerClass(type, abiType, kind, false); - return $$"""__{{arg}} = {{marshalerClass}}.CreateMarshaler({{arg}});"""; - } - else - { - string marshalerClass = GetMarshalerClass(type, abiType, kind, false); - return $$"""__{{arg}} = {{marshalerClass}}.CreateMarshaler2({{arg}});"""; - } - } - - public static string GetDisposeMarshaler(GenericParameter genericParameter, string arg) - { - return GetDisposeMarshaler( - genericParameter.ProjectedType, - genericParameter.AbiType, - genericParameter.TypeKind, - arg); - } - - public static string GetDisposeMarshaler(string type, string abiType, TypeKind kind, string arg) - { - if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType) || - type == "bool" || - type == "char") - { - return ""; - } - else - { - string marshalerClass = GetMarshalerClass(type, abiType, kind, false, true); - return $$"""{{marshalerClass}}.DisposeMarshaler(__{{arg}});"""; - } - } - - public static string GetAbiFromMarshaler(GenericParameter genericParameter, string arg) - { - return GetAbiFromMarshaler( - genericParameter.ProjectedType, - genericParameter.AbiType, - genericParameter.TypeKind, - arg); - } - - public static string GetAbiFromMarshaler(string type, string abiType, TypeKind kind, string arg) - { - if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType)) - { - return arg; - } - else if (type == "bool") - { - return $"(byte){arg}"; - } - else if (type == "char") - { - return $"(ushort){arg}"; - } - else - { - string marshalerClass = GetMarshalerClass(type, abiType, kind, false, true); - return $"{marshalerClass}.GetAbi(__{arg})"; - } - } - - public static string GetMarshalerDeclaration(GenericParameter genericParameter, string arg) - { - return GetMarshalerDeclaration( - genericParameter.ProjectedType, - genericParameter.AbiType, - genericParameter.TypeKind, - arg); - } - - public static string GetMarshalerDeclaration(string type, string abiType, TypeKind kind, string arg) - { - if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType) || - type == "bool" || - type == "char") - { - return ""; - } - else if (kind == TypeKind.Struct) - { - return $"{GetAbiMarshalerType(type, abiType, kind, false)}.Marshaler __{arg} = default;"; - } - else - { - return $"{GetAbiMarshalerType(type, abiType, kind, false)} __{arg} = default;"; - } - } - - public static string GetAbiMarshalerType(string type, string abiType, TypeKind kind, bool isArray) - { - if (type == "System.String" || type == "string") - { - return isArray ? "MarshalString.MarshalerArray" : "MarshalString"; - } - else if (type == "System.Type" || type == "Type") - { - if (isArray) - { - return "MarshalNonBlittable.MarshalerArray"; - } - else - { - return "global::ABI.System.Type.Marshaler"; - } - } - else if (type.StartsWith("System.Collections.Generic.KeyValuePair<")) - { - return isArray ? $$"""MarshalInterfaceHelper<{{type}}>.MarshalerArray""" : "ObjectReferenceValue"; - } - else if (kind == TypeKind.Enum) - { - return isArray ? $$"""MarshalBlittable<{{type}}>.MarshalerArray""" : type; - } - else if (kind == TypeKind.Struct) - { - if (type == abiType) - { - return isArray ? $$"""MarshalBlittable<{{type}}>.MarshalerArray""" : type; - } - else - { - return isArray ? $$"""MarshalNonBlittable<{{type}}>.MarshalerArray""" : "ABI." + type; - } - } - else if (type == "System.Object" || type == "object" || kind == TypeKind.Class || kind == TypeKind.Interface || kind == TypeKind.Delegate) - { - return isArray ? $$"""MarshalInterfaceHelper<{{type}}>.MarshalerArray""" : "ObjectReferenceValue"; - } - - throw new ArgumentException(); - } - - public static string EscapeAssemblyNameForIdentifier(string typeName) - { - return Regex.Replace(typeName, """[^a-zA-Z0-9_]""", "_"); - } - - public static string EscapeTypeNameForIdentifier(string typeName) - { - return Regex.Replace(typeName, """[(\ |:<>,\.\-@;+'^!`)]""", "_"); - } - - public readonly struct MappedType - { - private readonly string @namespace; - private readonly string name; - private readonly string assembly; - private readonly bool isSystemType; - private readonly bool isValueType; - private readonly bool isBlittable; - private readonly Func multipleMappingFunc; - - public MappedType(string @namespace, string name, string assembly, bool isValueType = false, bool isBlittable = false) - { - this.@namespace = @namespace; - this.name = name; - this.assembly = assembly; - isSystemType = string.CompareOrdinal(this.assembly, "mscorlib") == 0; - this.isValueType = isValueType; - this.isBlittable = isBlittable; - multipleMappingFunc = null; - } - - public MappedType(Func multipleMappingFunc) - { - @namespace = null; - name = null; - assembly = null; - isSystemType = false; - isValueType = false; - this.multipleMappingFunc = multipleMappingFunc; - } - - public (string, string, string, bool, bool) GetMapping(ISymbol containingType = null) - { - return multipleMappingFunc != null ? - multipleMappingFunc(containingType) : (@namespace, name, assembly, isSystemType, isValueType); - } - - public bool IsBlittable() - { - return isValueType && isBlittable; - } - } - - private static readonly Dictionary AsyncMethodToTaskAdapter = new() - { - // AsAsyncOperation is an extension method, due to that using the format of ReducedFrom. - { "System.WindowsRuntimeSystemExtensions.AsAsyncOperation(System.Threading.Tasks.Task)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run(System.Func>)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1"}, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromResult(TResult)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromException(System.Exception)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CanceledOperation()", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run(System.Func, System.Threading.Tasks.Task>)", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromResultWithProgress(TResult)", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromExceptionWithProgress(System.Exception)", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CanceledOperationWithProgress()", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run(System.Func, System.Threading.Tasks.Task>)", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CompletedActionWithProgress()", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromExceptionWithProgress(System.Exception)", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" }, - { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CanceledActionWithProgress()", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" } - }; - - public static string GetTaskAdapterIfAsyncMethod(IMethodSymbol symbol) - { - var symbolStr = symbol.IsExtensionMethod ? symbol.ReducedFrom?.ToDisplayString() : symbol.OriginalDefinition?.ToDisplayString(); - if (!string.IsNullOrEmpty(symbolStr)) - { - if (AsyncMethodToTaskAdapter.TryGetValue(symbolStr, out var adapterTypeStr)) - { - return adapterTypeStr; - } - } - - return null; - } - - public static string TrimGlobalFromTypeName(string typeName) - { - return typeName.StartsWith("global::") ? typeName[8..] : typeName; - } - } +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Generator +{ + public static class Helper + { + public static Guid EncodeGuid(byte[] data) + { + if (BitConverter.IsLittleEndian) + { + // swap bytes of int a + byte t = data[0]; + data[0] = data[3]; + data[3] = t; + t = data[1]; + data[1] = data[2]; + data[2] = t; + // swap bytes of short b + t = data[4]; + data[4] = data[5]; + data[5] = t; + // swap bytes of short c and encode rfc time/version field + t = data[6]; + data[6] = data[7]; + data[7] = (byte)((t & 0x0f) | (5 << 4)); + // encode rfc clock/reserved field + data[8] = (byte)((data[8] & 0x3f) | 0x80); + } + return new Guid(data.Take(16).ToArray()); + } + } + + class AttributeDataComparer : IEqualityComparer + { + public bool Equals(AttributeData x, AttributeData y) + { + return string.CompareOrdinal(x.ToString(), y.ToString()) == 0; + } + + public int GetHashCode(AttributeData obj) + { + return obj.ToString().GetHashCode(); + } + } + + static class GeneratorExecutionContextHelper + { + public static string GetAssemblyName(this GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyName", out var assemblyName); + return assemblyName; + } + + public static string GetAssemblyVersion(this GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyVersion", out var assemblyVersion); + return assemblyVersion; + } + + [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "We need to do file IO to invoke the 'cswinrt' tool.")] + public static string GetGeneratedFilesDir(this GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTGeneratedFilesDir", out var generatedFilesDir); + Directory.CreateDirectory(generatedFilesDir); + return generatedFilesDir; + } + + public static string GetCsWinRTExeTFM(this GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTExeTFM", out var csWinRTExeTFM); + return csWinRTExeTFM; + } + + public static bool IsCsWinRTComponent(this GeneratorExecutionContext context) + { + if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTComponent", out var isCsWinRTComponentStr)) + { + return bool.TryParse(isCsWinRTComponentStr, out var isCsWinRTComponent) && isCsWinRTComponent; + } + + return false; + } + + public static bool IsCsWinRTComponent(this AnalyzerConfigOptionsProvider provider) + { + if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTComponent", out var isCsWinRTComponentStr)) + { + return bool.TryParse(isCsWinRTComponentStr, out var isCsWinRTComponent) && isCsWinRTComponent; + } + + return false; + } + + public static bool IsCsWinRTAotOptimizerEnabled(this AnalyzerConfigOptionsProvider provider) + { + if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTAotOptimizerEnabled", out var isCsWinRTAotOptimizerEnabledStr)) + { + return (bool.TryParse(isCsWinRTAotOptimizerEnabledStr, out var isCsWinRTAotOptimizerEnabled) && isCsWinRTAotOptimizerEnabled) || + string.Equals(isCsWinRTAotOptimizerEnabledStr, "OptIn", StringComparison.OrdinalIgnoreCase) || + string.Equals(isCsWinRTAotOptimizerEnabledStr, "Auto", StringComparison.OrdinalIgnoreCase); + } + + return false; + } + + private enum CsWinRTAotOptimizerMode + { + Disabled = 0, + OptIn = 1, + Auto = 2, + Default = 3, + } + + public static bool IsCsWinRTAotOptimizerInAutoMode(AnalyzerConfigOptionsProvider provider, Compilation compilation) + { + var mode = GetMode(provider); + + if (mode == CsWinRTAotOptimizerMode.Default) + { + // If mode is default and this is a WinUI or UWP project, which we detect by using the Button type as a marker, + // then AOT optimizer is running in auto mode because in both projects the main API boundary is WinRT. + // For CsWinRT components, we also run by default in auto mode. + return provider.IsCsWinRTComponent() || + compilation.GetTypeByMetadataName("Microsoft.UI.Xaml.Controls.Button") is not null || + compilation.GetTypeByMetadataName("Windows.UI.Xaml.Controls.Button") is not null || + // If warning level was explicitly set to 2 without a mode set, + // we don't want to change the behavior of those projects who were + // relying on it running. If they set the mode, then the mode would + // be respected. + provider.GetCsWinRTAotWarningLevel() == 2; + } + + // If mode is not the default, check if it is set explicitly to Auto. + return mode == CsWinRTAotOptimizerMode.Auto; + + static CsWinRTAotOptimizerMode GetMode(AnalyzerConfigOptionsProvider provider) + { + if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTAotOptimizerEnabled", out var isCsWinRTAotOptimizerEnabledStr)) + { + if (string.Equals(isCsWinRTAotOptimizerEnabledStr, "OptIn", StringComparison.OrdinalIgnoreCase)) + { + return CsWinRTAotOptimizerMode.OptIn; + } + + if (string.Equals(isCsWinRTAotOptimizerEnabledStr, "Auto", StringComparison.OrdinalIgnoreCase)) + { + return CsWinRTAotOptimizerMode.Auto; + } + + if (bool.TryParse(isCsWinRTAotOptimizerEnabledStr, out var isCsWinRTAotOptimizerEnabled) && isCsWinRTAotOptimizerEnabled) + { + return CsWinRTAotOptimizerMode.Default; + } + } + + return CsWinRTAotOptimizerMode.Disabled; + } + } + + public static bool GetCsWinRTRcwFactoryFallbackGeneratorForceOptIn(this AnalyzerConfigOptionsProvider provider) + { + if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTRcwFactoryFallbackGeneratorForceOptIn", out var csWinRTRcwFactoryFallbackGeneratorForceOptIn)) + { + return bool.TryParse(csWinRTRcwFactoryFallbackGeneratorForceOptIn, out var isCsWinRTRcwFactoryFallbackGeneratorForceOptIn) && isCsWinRTRcwFactoryFallbackGeneratorForceOptIn; + } + + return false; + } + + public static bool GetCsWinRTMergeReferencedActivationFactories(this AnalyzerConfigOptionsProvider provider) + { + if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTMergeReferencedActivationFactories", out var csWinRTMergeReferencedActivationFactories)) + { + return bool.TryParse(csWinRTMergeReferencedActivationFactories, out var isCsWinRTMergeReferencedActivationFactories) && isCsWinRTMergeReferencedActivationFactories; + } + + return false; + } + + public static bool GetCsWinRTRcwFactoryFallbackGeneratorForceOptOut(this AnalyzerConfigOptionsProvider provider) + { + if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTRcwFactoryFallbackGeneratorForceOptOut", out var csWinRTRcwFactoryFallbackGeneratorForceOptOut)) + { + return bool.TryParse(csWinRTRcwFactoryFallbackGeneratorForceOptOut, out var isCsWinRTRcwFactoryFallbackGeneratorForceOptOut) && isCsWinRTRcwFactoryFallbackGeneratorForceOptOut; + } + + return false; + } + + public static bool IsCsWinRTCcwLookupTableGeneratorEnabled(this AnalyzerConfigOptionsProvider provider) + { + if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTCcwLookupTableGeneratorEnabled", out var csWinRTCcwLookupTableGeneratorEnabled)) + { + return bool.TryParse(csWinRTCcwLookupTableGeneratorEnabled, out var isCsWinRTCcwLookupTableGeneratorEnabled) && isCsWinRTCcwLookupTableGeneratorEnabled; + } + + return false; + } + + public static bool GetCsWinRTUseWindowsUIXamlProjections(this AnalyzerConfigOptionsProvider provider) + { + if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTUseWindowsUIXamlProjections", out var csWinRTUseWindowsUIXamlProjections)) + { + return bool.TryParse(csWinRTUseWindowsUIXamlProjections, out var isCsWinRTUseWindowsUIXamlProjectionsEnabled) && isCsWinRTUseWindowsUIXamlProjectionsEnabled; + } + + return false; + } + + public static int GetCsWinRTAotWarningLevel(this AnalyzerConfigOptionsProvider provider) + { + if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTAotWarningLevel", out var csWinRTAotWarningLevelStr) && + int.TryParse(csWinRTAotWarningLevelStr, out var csWinRTAotWarningLevel)) + { + return csWinRTAotWarningLevel; + } + + return 0; + } + + public static bool ShouldGenerateWinMDOnly(this GeneratorExecutionContext context) + { + if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTGenerateWinMDOnly", out var CsWinRTGenerateWinMDOnlyStr)) + { + return bool.TryParse(CsWinRTGenerateWinMDOnlyStr, out var CsWinRTGenerateWinMDOnly) && CsWinRTGenerateWinMDOnly; + } + + return false; + } + + /// + /// Gets whether the "CsWinRTAotExportsEnabled" MSBuild property is defined. + /// + /// The input value to use. + /// Whether the "CsWinRTAotExportsEnabled" MSBuild property is defined. + public static bool ShouldGenerateWinRTNativeExports(this GeneratorExecutionContext context) + { + if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTAotExportsEnabled", out var isCsWinRTAotExportsEnabledStr)) + { + return bool.TryParse(isCsWinRTAotExportsEnabledStr, out var isCsWinRTAotExportsEnabled) && isCsWinRTAotExportsEnabled; + } + + return false; + } + + public static string GetCsWinRTExe(this GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTExe", out var cswinrtExe); + return cswinrtExe; + } + + public static bool GetKeepGeneratedSources(this GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTKeepGeneratedSources", out var keepGeneratedSourcesStr); + return keepGeneratedSourcesStr != null && bool.TryParse(keepGeneratedSourcesStr, out var keepGeneratedSources) && keepGeneratedSources; + } + + public static string GetCsWinRTWindowsMetadata(this GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTWindowsMetadata", out var cswinrtWindowsMetadata); + return cswinrtWindowsMetadata; + } + + public static string GetCsWinRTDependentMetadata(this GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTAuthoringInputs", out var winmds); + return winmds; + } + + public static string GetWinmdOutputFile(this GeneratorExecutionContext context) + { + var fileName = context.GetAssemblyName(); + if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTWinMDOutputFile", out var ret)) + { + fileName = ret!; + } + return Path.Combine(context.GetGeneratedFilesDir(), fileName + ".winmd"); + } + + public static bool GetCsWinRTMergeReferencedActivationFactories(this GeneratorExecutionContext context) + { + if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTMergeReferencedActivationFactories", out var csWinRTMergeReferencedActivationFactories)) + { + return bool.TryParse(csWinRTMergeReferencedActivationFactories, out var isCsWinRTMergeReferencedActivationFactories) && isCsWinRTMergeReferencedActivationFactories; + } + + return false; + } + } + + static class GeneratorHelper + { + private static bool IsFundamentalType(ISymbol type) + { + if (type is INamedTypeSymbol namedTypeSymbol) + { + switch (namedTypeSymbol.SpecialType) + { + case SpecialType.System_Boolean: + case SpecialType.System_String: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_UInt16: + case SpecialType.System_UInt32: + case SpecialType.System_UInt64: + case SpecialType.System_Int16: + case SpecialType.System_Int32: + case SpecialType.System_Int64: + case SpecialType.System_Char: + case SpecialType.System_Byte: + case SpecialType.System_Object: + return true; + } + } + + return type.ToDisplayString() == "System.Guid"; + } + + /// + /// Checks whether an assembly contains old projections. + /// + /// The assembly to inspect. + /// Whether contains old projections. + public static bool IsOldProjectionAssembly(IAssemblySymbol assemblySymbol) + { + // We only care about assemblies that have some dependent assemblies + if (assemblySymbol.Modules.First() is not { ReferencedAssemblies: { Length: > 0 } dependentAssemblies }) + { + return false; + } + + // Scan all dependent assemblies to look for CsWinRT with version < 2.0.8 + foreach (AssemblyIdentity assemblyIdentity in dependentAssemblies) + { + if (assemblyIdentity.Name == "WinRT.Runtime") + { + return assemblyIdentity.Version < new Version(2, 0, 8) && + assemblyIdentity.Version != new Version(0, 0, 0, 0); + } + } + + // This assembly is not a projection assembly + return false; + } + + public static bool IsOldCsWinRTExe(GeneratorExecutionContext context) + { + string cswinrtExe = context.GetCsWinRTExe(); + var cswinrtExeVersion = new Version(FileVersionInfo.GetVersionInfo(cswinrtExe).FileVersion); + return cswinrtExeVersion < new Version(2, 1, 0) && cswinrtExeVersion != new Version(0, 0, 0, 0); + } + + public static bool AllowUnsafe(Compilation compilation) + { + return compilation is CSharpCompilation csharpCompilation && csharpCompilation.Options.AllowUnsafe; + } + + // Returns whether it is a WinRT class or interface. + // If the bool parameter is true, then custom mapped interfaces are also considered. + // This function is similar to whether it is a WinRT type, but custom type mapped + // classes are excluded given those are C# implemented classes such as string. + public static Func IsWinRTClassOrInterface(Compilation compilation, Func isWinRTType, TypeMapper mapper) + { + var winrtRuntimeTypeAttribute = compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute"); + return IsWinRTClassOrInterfaceHelper; + + bool IsWinRTClassOrInterfaceHelper(ISymbol type, bool includeMappedInterfaces) + { + if (type is ITypeSymbol typeSymbol && typeSymbol.TypeKind == TypeKind.Interface) + { + return isWinRTType(type, mapper); + } + + return HasAttributeWithType(type, winrtRuntimeTypeAttribute); + } + } + + public static bool IsWinRTType(ISymbol type, TypeMapper mapper) + { + return IsWinRTType(type, null, mapper); + } + + public static bool IsWinRTType(ISymbol type, Func isAuthoringWinRTType, TypeMapper mapper) + { + bool isProjectedType = type.GetAttributes(). + Any(static attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeTypeAttribute") == 0) || + IsFundamentalType(type); + + if (!isProjectedType & type.ContainingNamespace != null) + { + isProjectedType = mapper.HasMappingForType(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); + } + + // Ensure all generic parameters are WinRT types. + if (isProjectedType && type is INamedTypeSymbol namedType && namedType.IsGenericType && !namedType.IsDefinition) + { + isProjectedType = namedType.TypeArguments.All(t => + IsWinRTType(t, isAuthoringWinRTType, mapper) || + (isAuthoringWinRTType != null && isAuthoringWinRTType(t, mapper))); + } + + return isProjectedType; + } + + public static bool IsWinRTType(ISymbol type, ITypeSymbol winrtRuntimeTypeAttribute, TypeMapper mapper, bool isComponentProject, IAssemblySymbol currentAssembly) + { + if (IsFundamentalType(type)) + { + return true; + } + + if (isComponentProject && + // Make sure type is in component project. + SymbolEqualityComparer.Default.Equals(type.ContainingAssembly, currentAssembly) && + type.DeclaredAccessibility == Accessibility.Public) + { + // Authoring diagnostics will make sure all public types are valid WinRT types. + return true; + } + + bool isProjectedType = HasAttributeWithType(type, winrtRuntimeTypeAttribute); + if (!isProjectedType & type.ContainingNamespace != null) + { + isProjectedType = mapper.HasMappingForType(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); + } + + // Ensure all generic parameters are WinRT types. + if (isProjectedType && + type is INamedTypeSymbol namedType && + namedType.IsGenericType && + !namedType.IsDefinition) + { + isProjectedType = namedType.TypeArguments.All(t => IsWinRTType(t, winrtRuntimeTypeAttribute, mapper, isComponentProject, currentAssembly)); + } + + return isProjectedType; + } + + public static bool IsWinRTTypeOrImplementsWinRTType(ISymbol type, ITypeSymbol winrtRuntimeTypeAttribute, TypeMapper mapper, bool isComponentProject, IAssemblySymbol currentAssembly) + { + if (IsWinRTType(type, winrtRuntimeTypeAttribute, mapper, isComponentProject, currentAssembly)) + { + return true; + } + + if (type is INamedTypeSymbol namedType && + namedType.AllInterfaces.Any(iface => IsWinRTType(iface, winrtRuntimeTypeAttribute, mapper, isComponentProject, currentAssembly))) + { + return true; + } + + return false; + } + + // Assuming a type is a WinRT type, this determines whether it is a WinRT type from custom type mappings. + // i.e Whether it is a built-in type that is also a WinRT type. + public static bool IsCustomMappedType(ISymbol type, TypeMapper mapper) + { + if (IsFundamentalType(type)) + { + return true; + } + + bool isCustomMappedType = false; + if (type.ContainingNamespace != null) + { + isCustomMappedType = mapper.HasMappingForType(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); + } + + // Ensure all generic parameters are WinRT types. + if (isCustomMappedType && + type is INamedTypeSymbol namedType && + namedType.IsGenericType && + !namedType.IsDefinition) + { + isCustomMappedType = namedType.TypeArguments.All(t => IsCustomMappedType(t, mapper)); + } + + return isCustomMappedType; + } + + // Checks if the interface references any internal types (either the interface itself or within its generic types). + public static bool IsInternalInterfaceFromReferences(INamedTypeSymbol iface, IAssemblySymbol currentAssembly) + { + if (iface.DeclaredAccessibility == Accessibility.Internal && + !SymbolEqualityComparer.Default.Equals(iface.ContainingAssembly, currentAssembly)) + { + return true; + } + + if (iface.IsGenericType) + { + // Making use of HashSet to avoid checking multiple times for same type and to avoid doing recursive calls. + HashSet genericArgumentsToProcess = new(iface.TypeArguments, SymbolEqualityComparer.Default); + HashSet visitedTypes = new(SymbolEqualityComparer.Default); + while (genericArgumentsToProcess.Count != 0) + { + var currentType = genericArgumentsToProcess.First(); + visitedTypes.Add(currentType); + genericArgumentsToProcess.Remove(currentType); + + if (currentType.DeclaredAccessibility == Accessibility.Internal && + !SymbolEqualityComparer.Default.Equals(currentType.ContainingAssembly, currentAssembly)) + { + return true; + } + + if (currentType is INamedTypeSymbol currentNamedTypeSymbol) + { + if (currentNamedTypeSymbol.IsGenericType) + { + foreach (var typeArgument in currentNamedTypeSymbol.TypeArguments) + { + if (!visitedTypes.Contains(typeArgument)) + { + genericArgumentsToProcess.Add(typeArgument); + } + } + } + } + } + } + + return false; + } + + // Checks whether the symbol references any generic that hasn't been instantiated + // and is used by a WinRT interface. For instance, List where T is a generic. + // If the generic isn't used by any WinRT interface, this returns false as for + // instance, we can still generate the vtable attribute for it. + public static bool HasNonInstantiatedWinRTGeneric(ITypeSymbol symbol, TypeMapper mapper) + { + return symbol is INamedTypeSymbol namedType && + (IsArgumentTypeParameter(namedType) || + (namedType.TypeArguments.Any(IsArgumentTypeParameter) && + namedType.AllInterfaces.Any(iface => iface.TypeArguments.Any(IsArgumentTypeParameter) && + // Checks if without the non-instantiated generic, whether it would be a WinRT type. + IsWinRTType(iface.OriginalDefinition, null, mapper)))); + + static bool IsArgumentTypeParameter(ITypeSymbol argument) + { + return argument.TypeKind == TypeKind.TypeParameter; + } + } + + public static bool IsPartial(INamedTypeSymbol symbol) + { + bool isPartial = true; + for (ITypeSymbol parent = symbol; parent is not null; parent = parent.ContainingType) + { + isPartial &= parent.DeclaringSyntaxReferences.Any( + static syntax => syntax.GetSyntax() is BaseTypeDeclarationSyntax declaration && + declaration.Modifiers.Any(SyntaxKind.PartialKeyword)); + } + return isPartial; + } + + public static bool IsPartial(TypeDeclarationSyntax node) + { + bool isPartial = true; + for (TypeDeclarationSyntax parent = node; parent is not null; parent = parent.Parent as TypeDeclarationSyntax) + { + isPartial &= parent.Modifiers.Any(static m => m.IsKind(SyntaxKind.PartialKeyword)); + } + return isPartial; + } + + public static bool HasPrivateclass(ITypeSymbol symbol) + { + return symbol is INamedTypeSymbol namedType && + (namedType.DeclaredAccessibility == Accessibility.Private || + namedType.TypeArguments.Any(static argument => argument.DeclaredAccessibility == Accessibility.Private)); + } + + public static bool HasWinRTExposedTypeAttribute(ISymbol type) + { + return type.GetAttributes(). + Any(static attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WinRTExposedTypeAttribute") == 0); + } + + public static bool HasWinRTRuntimeClassNameAttribute(ISymbol type, Compilation compilation) + { + var winrtRuntimeClassNameAttribute = compilation.GetTypeByMetadataName("WinRT.WinRTRuntimeClassNameAttribute"); + if (winrtRuntimeClassNameAttribute is null) + { + return false; + } + + return HasAttributeWithType(type, winrtRuntimeClassNameAttribute); + } + + public static bool IsWinRTType(MemberDeclarationSyntax node) + { + bool isProjectedType = node.AttributeLists.SelectMany(static list => list.Attributes). + Any(static attribute => string.CompareOrdinal(attribute.Name.NormalizeWhitespace().ToFullString(), "global::WinRT.WindowsRuntimeType") == 0); + return isProjectedType; + } + + public static bool HasBindableCustomPropertyAttribute(MemberDeclarationSyntax node) + { + return node.AttributeLists.SelectMany(static list => list.Attributes).Any(IsBindableCustomPropertyAttribute); + + // Check based on identifier name if this is the GeneratedBindableCustomProperty attribute. + // Technically this can be a different namespace, but we will confirm later once + // we have access to the semantic model. + static bool IsBindableCustomPropertyAttribute(AttributeSyntax attribute) + { + var nameSyntax = attribute.Name; + if (nameSyntax is QualifiedNameSyntax qualifiedName) + { + // Right would have the attribute while left is the namespace. + nameSyntax = qualifiedName.Right; + } + + return nameSyntax is IdentifierNameSyntax name && + (name.Identifier.ValueText == "GeneratedBindableCustomProperty" || + name.Identifier.ValueText == "GeneratedBindableCustomPropertyAttribute"); + } + } + + /// + /// Checks whether or not a given symbol has an attribute with the specified type. + /// + /// The input instance to check. + /// The instance for the attribute type to look for. + /// Whether or not has an attribute with the specified type. + public static bool HasAttributeWithType(ISymbol symbol, ITypeSymbol attributeTypeSymbol) + { + foreach (AttributeData attribute in symbol.GetAttributes()) + { + if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, attributeTypeSymbol)) + { + return true; + } + } + + return false; + } + + /// + /// Checks whether a symbol is annotated with [WinRTExposedType(typeof(WinRTManagedOnlyTypeDetails))]. + /// + public static bool IsManagedOnlyType(ISymbol symbol, ITypeSymbol winrtExposedTypeAttribute, ITypeSymbol winrtManagedOnlyTypeDetails) + { + foreach (AttributeData attribute in symbol.GetAttributes()) + { + if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, winrtExposedTypeAttribute)) + { + if (attribute.ConstructorArguments is [{ Kind: TypedConstantKind.Type, Type: ITypeSymbol exposedTypeDetails }] && + SymbolEqualityComparer.Default.Equals(exposedTypeDetails, winrtManagedOnlyTypeDetails)) + { + return true; + } + + // A type can have just one [WinRTExposedType] attribute. If the details are not WinRTManagedOnlyTypeDetails, + // we can immediatley stop here and avoid checking all remaining attributes, as we couldn't possibly match. + return false; + } + } + + return false; + } + + public static Func IsWinRTType(Compilation compilation, bool isComponentProject) + { + var winrtTypeAttribute = compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute"); + return IsWinRTTypeHelper; + + bool IsWinRTTypeHelper(ISymbol type, TypeMapper typeMapper) + { + return IsWinRTType(type, winrtTypeAttribute, typeMapper, isComponentProject, compilation.Assembly); + } + } + + public static Func IsManagedOnlyType(Compilation compilation) + { + var winrtExposedTypeAttribute = compilation.GetTypeByMetadataName("WinRT.WinRTExposedTypeAttribute"); + var winrtManagedOnlyTypeDetails = compilation.GetTypeByMetadataName("WinRT.WinRTManagedOnlyTypeDetails"); + + return IsManagedOnlyTypeHelper; + + bool IsManagedOnlyTypeHelper(ISymbol type) + { + return IsManagedOnlyType(type, winrtExposedTypeAttribute, winrtManagedOnlyTypeDetails); + } + } + + private static string GetAbiTypeForFundamentalType(ISymbol type) + { + if (type is INamedTypeSymbol namedTypeSymbol) + { + switch (namedTypeSymbol.SpecialType) + { + case SpecialType.System_Boolean: + return "byte"; + case SpecialType.System_String: + return "IntPtr"; + case SpecialType.System_Char: + return "ushort"; + case SpecialType.System_Object: + return "IntPtr"; + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_UInt16: + case SpecialType.System_UInt32: + case SpecialType.System_UInt64: + case SpecialType.System_Int16: + case SpecialType.System_Int32: + case SpecialType.System_Int64: + case SpecialType.System_Byte: + return type.ToDisplayString(); + } + } + + return type.ToDisplayString(); + } + + public static bool IsBlittableValueType(ITypeSymbol type, TypeMapper typeMapper) + { + if (!type.IsValueType) + { + return false; + } + + if (type.SpecialType != SpecialType.None) + { + switch (type.SpecialType) + { + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_UInt16: + case SpecialType.System_UInt32: + case SpecialType.System_UInt64: + case SpecialType.System_Int16: + case SpecialType.System_Int32: + case SpecialType.System_Int64: + case SpecialType.System_Byte: + case SpecialType.System_SByte: + case SpecialType.System_IntPtr: + case SpecialType.System_UIntPtr: + return true; + default: + return false; + } + } + + if (type.ContainingNamespace != null) + { + string customTypeMapKey = string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName); + if (typeMapper.HasMappingForType(customTypeMapKey)) + { + return typeMapper.GetMappedType(customTypeMapKey).IsBlittable(); + } + } + + if (type.TypeKind == TypeKind.Enum) + { + return true; + } + + if (type.TypeKind == TypeKind.Struct) + { + foreach (var typeMember in type.GetMembers()) + { + if (typeMember is IFieldSymbol field && + !field.IsStatic && + !IsBlittableValueType(field.Type, typeMapper)) + { + return false; + } + } + } + return true; + } + + public static string GetAbiType(ITypeSymbol type, TypeMapper mapper) + { + if (IsFundamentalType(type)) + { + return GetAbiTypeForFundamentalType(type); + } + + var typeStr = type.ToDisplayString(); + if (typeStr == "System.Type") + { + return "ABI.System.Type"; + } + else if (typeStr.StartsWith("System.Collections.Generic.KeyValuePair<")) + { + return "IntPtr"; + } + else if (typeStr == "System.Exception") + { + return "ABI.System.Exception"; + } + + if (type.IsValueType && !type.NullableAnnotation.HasFlag(NullableAnnotation.Annotated)) + { + string customTypeMapKey = string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName); + if (mapper.HasMappingForType(customTypeMapKey)) + { + string prefix = mapper.GetMappedType(customTypeMapKey).IsBlittable() ? "" : "ABI."; + return prefix + typeStr; + } + + if (!IsBlittableValueType(type, mapper)) + { + var winrtHelperAttribute = type.GetAttributes(). + Where(static attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeHelperTypeAttribute") == 0). + FirstOrDefault(); + if (winrtHelperAttribute != null && + winrtHelperAttribute.ConstructorArguments.Any()) + { + return winrtHelperAttribute.ConstructorArguments[0].Value.ToString(); + } + // Handling authoring scenario where Impl type has the attributes and + // if the current component is the one being authored, it may not be + // generated yet to check given it is the same compilation. + else + { + return "ABI." + typeStr; + } + } + else + { + return typeStr; + } + } + + return "IntPtr"; + } + + public static string GetMarshalerClass(string type, string abiType, TypeKind kind, bool isArray, bool useGenericMarshaler = false) + { + if (type == "System.String" || type == "string") + { + return "MarshalString"; + } + else if (type == "System.Type" || type == "Type") + { + if (isArray) + { + return "MarshalNonBlittable"; + } + else + { + return "global::ABI.System.Type"; + } + } + else if (type == "System.Exception" || type == "Exception") + { + if (isArray) + { + return "MarshalNonBlittable"; + } + else + { + return "global::ABI.System.Exception"; + } + } + else if (type == "System.Object" || type == "object") + { + return "MarshalInspectable"; + } + else if (type.StartsWith("System.Collections.Generic.KeyValuePair<")) + { + return $$"""MarshalInterface<{{type}}>"""; + } + else if (kind == TypeKind.Enum) + { + if (isArray) + { + return $$"""MarshalBlittable<{{type}}>"""; + } + else + { + return ""; + } + } + else if (kind == TypeKind.Struct) + { + if (type == abiType) + { + if (isArray) + { + return $$"""MarshalBlittable<{{type}}>"""; + } + else + { + return ""; + } + } + else + { + if (isArray) + { + return $$"""MarshalNonBlittable<{{type}}>"""; + } + else + { + return "global::ABI." + type; + } + } + } + else if (kind == TypeKind.Interface) + { + return $$"""MarshalInterface<{{type}}>"""; + } + else if (kind == TypeKind.Class || kind == TypeKind.Delegate) + { + return useGenericMarshaler ? "MarshalInspectable" : "global::ABI." + type; + } + + throw new ArgumentException(); + } + + public static string GetFromAbiMarshaler(GenericParameter genericParameter, string arg) + { + return GetFromAbiMarshaler( + genericParameter.ProjectedType, + genericParameter.AbiType, + genericParameter.TypeKind, + arg); + } + + public static string GetFromAbiMarshaler(string type, string abiType, TypeKind kind, string arg) + { + string marshalerType = GetMarshalerClass(type, abiType, kind, false); + if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType)) + { + return arg; + } + else if (type == "bool") + { + return $$"""({{arg}} != 0)"""; + } + else if (type == "char") + { + return $$"""(char){{arg}}"""; + } + else + { + return $$"""{{marshalerType}}.FromAbi({{arg}})"""; + } + } + + public static string GetFromManagedMarshaler(GenericParameter genericParameter, string arg) + { + return GetFromManagedMarshaler( + genericParameter.ProjectedType, + genericParameter.AbiType, + genericParameter.TypeKind, + arg); + } + + public static string GetFromManagedMarshaler(string type, string abiType, TypeKind kind, string arg) + { + string marshalerType = GetMarshalerClass(type, abiType, kind, false); + if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType)) + { + return arg; + } + else if (type == "bool") + { + return $$"""(byte)({{arg}} ? 1 : 0)"""; + } + else if (type == "char") + { + return $$"""(ushort){{arg}}"""; + } + else + { + return $$"""{{marshalerType}}.FromManaged({{arg}})"""; + } + } + + public static string GetCopyManagedArrayMarshaler(string type, string abiType, TypeKind kind) + { + if (kind == TypeKind.Class || kind == TypeKind.Delegate) + { + // TODO: Classes and delegates are missing CopyManagedArray. + return $$"""Marshaler<{{type}}>"""; + } + else + { + return GetMarshalerClass(type, abiType, kind, true); + } + } + + public static string GetCreateMarshaler(GenericParameter genericParameter, string arg) + { + return GetCreateMarshaler( + genericParameter.ProjectedType, + genericParameter.AbiType, + genericParameter.TypeKind, + arg); + } + + public static string GetCreateMarshaler(string type, string abiType, TypeKind kind, string arg) + { + if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType) || + type == "bool" || + type == "char") + { + return ""; + } + else if (type == "System.String" || type == "string") + { + // TODO: Consider switching to pinning + return $$"""__{{arg}} = MarshalString.CreateMarshaler({{arg}});"""; + } + else if (kind == TypeKind.Struct) + { + string marshalerClass = GetMarshalerClass(type, abiType, kind, false); + return $$"""__{{arg}} = {{marshalerClass}}.CreateMarshaler({{arg}});"""; + } + else + { + string marshalerClass = GetMarshalerClass(type, abiType, kind, false); + return $$"""__{{arg}} = {{marshalerClass}}.CreateMarshaler2({{arg}});"""; + } + } + + public static string GetDisposeMarshaler(GenericParameter genericParameter, string arg) + { + return GetDisposeMarshaler( + genericParameter.ProjectedType, + genericParameter.AbiType, + genericParameter.TypeKind, + arg); + } + + public static string GetDisposeMarshaler(string type, string abiType, TypeKind kind, string arg) + { + if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType) || + type == "bool" || + type == "char") + { + return ""; + } + else + { + string marshalerClass = GetMarshalerClass(type, abiType, kind, false, true); + return $$"""{{marshalerClass}}.DisposeMarshaler(__{{arg}});"""; + } + } + + public static string GetAbiFromMarshaler(GenericParameter genericParameter, string arg) + { + return GetAbiFromMarshaler( + genericParameter.ProjectedType, + genericParameter.AbiType, + genericParameter.TypeKind, + arg); + } + + public static string GetAbiFromMarshaler(string type, string abiType, TypeKind kind, string arg) + { + if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType)) + { + return arg; + } + else if (type == "bool") + { + return $"(byte){arg}"; + } + else if (type == "char") + { + return $"(ushort){arg}"; + } + else + { + string marshalerClass = GetMarshalerClass(type, abiType, kind, false, true); + return $"{marshalerClass}.GetAbi(__{arg})"; + } + } + + public static string GetMarshalerDeclaration(GenericParameter genericParameter, string arg) + { + return GetMarshalerDeclaration( + genericParameter.ProjectedType, + genericParameter.AbiType, + genericParameter.TypeKind, + arg); + } + + public static string GetMarshalerDeclaration(string type, string abiType, TypeKind kind, string arg) + { + if (kind == TypeKind.Enum || (kind == TypeKind.Struct && type == abiType) || + type == "bool" || + type == "char") + { + return ""; + } + else if (kind == TypeKind.Struct) + { + return $"{GetAbiMarshalerType(type, abiType, kind, false)}.Marshaler __{arg} = default;"; + } + else + { + return $"{GetAbiMarshalerType(type, abiType, kind, false)} __{arg} = default;"; + } + } + + public static string GetAbiMarshalerType(string type, string abiType, TypeKind kind, bool isArray) + { + if (type == "System.String" || type == "string") + { + return isArray ? "MarshalString.MarshalerArray" : "MarshalString"; + } + else if (type == "System.Type" || type == "Type") + { + if (isArray) + { + return "MarshalNonBlittable.MarshalerArray"; + } + else + { + return "global::ABI.System.Type.Marshaler"; + } + } + else if (type.StartsWith("System.Collections.Generic.KeyValuePair<")) + { + return isArray ? $$"""MarshalInterfaceHelper<{{type}}>.MarshalerArray""" : "ObjectReferenceValue"; + } + else if (kind == TypeKind.Enum) + { + return isArray ? $$"""MarshalBlittable<{{type}}>.MarshalerArray""" : type; + } + else if (kind == TypeKind.Struct) + { + if (type == abiType) + { + return isArray ? $$"""MarshalBlittable<{{type}}>.MarshalerArray""" : type; + } + else + { + return isArray ? $$"""MarshalNonBlittable<{{type}}>.MarshalerArray""" : "ABI." + type; + } + } + else if (type == "System.Object" || type == "object" || kind == TypeKind.Class || kind == TypeKind.Interface || kind == TypeKind.Delegate) + { + return isArray ? $$"""MarshalInterfaceHelper<{{type}}>.MarshalerArray""" : "ObjectReferenceValue"; + } + + throw new ArgumentException(); + } + + public static string EscapeAssemblyNameForIdentifier(string typeName) + { + return Regex.Replace(typeName, """[^a-zA-Z0-9_]""", "_"); + } + + public static string EscapeTypeNameForIdentifier(string typeName) + { + return Regex.Replace(typeName, """[(\ |:<>,\.\-@;+'^!`)]""", "_"); + } + + public readonly struct MappedType + { + private readonly string @namespace; + private readonly string name; + private readonly string assembly; + private readonly bool isSystemType; + private readonly bool isValueType; + private readonly bool isBlittable; + private readonly Func multipleMappingFunc; + + public MappedType(string @namespace, string name, string assembly, bool isValueType = false, bool isBlittable = false) + { + this.@namespace = @namespace; + this.name = name; + this.assembly = assembly; + isSystemType = string.CompareOrdinal(this.assembly, "mscorlib") == 0; + this.isValueType = isValueType; + this.isBlittable = isBlittable; + multipleMappingFunc = null; + } + + public MappedType(Func multipleMappingFunc) + { + @namespace = null; + name = null; + assembly = null; + isSystemType = false; + isValueType = false; + this.multipleMappingFunc = multipleMappingFunc; + } + + public (string, string, string, bool, bool) GetMapping(ISymbol containingType = null) + { + return multipleMappingFunc != null ? + multipleMappingFunc(containingType) : (@namespace, name, assembly, isSystemType, isValueType); + } + + public bool IsBlittable() + { + return isValueType && isBlittable; + } + } + + private static readonly Dictionary AsyncMethodToTaskAdapter = new() + { + // AsAsyncOperation is an extension method, due to that using the format of ReducedFrom. + { "System.WindowsRuntimeSystemExtensions.AsAsyncOperation(System.Threading.Tasks.Task)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run(System.Func>)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1"}, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromResult(TResult)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromException(System.Exception)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CanceledOperation()", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run(System.Func, System.Threading.Tasks.Task>)", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromResultWithProgress(TResult)", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromExceptionWithProgress(System.Exception)", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CanceledOperationWithProgress()", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run(System.Func, System.Threading.Tasks.Task>)", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CompletedActionWithProgress()", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromExceptionWithProgress(System.Exception)", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" }, + { "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CanceledActionWithProgress()", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" } + }; + + public static string GetTaskAdapterIfAsyncMethod(IMethodSymbol symbol) + { + var symbolStr = symbol.IsExtensionMethod ? symbol.ReducedFrom?.ToDisplayString() : symbol.OriginalDefinition?.ToDisplayString(); + if (!string.IsNullOrEmpty(symbolStr)) + { + if (AsyncMethodToTaskAdapter.TryGetValue(symbolStr, out var adapterTypeStr)) + { + return adapterTypeStr; + } + } + + return null; + } + + public static string TrimGlobalFromTypeName(string typeName) + { + return typeName.StartsWith("global::") ? typeName[8..] : typeName; + } + } } \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ImmutableEquatableArray.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ImmutableEquatableArray.cs similarity index 97% rename from src/Authoring/WinRT.SourceGenerator/ImmutableEquatableArray.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ImmutableEquatableArray.cs index 4d879b679..b3bbaa84d 100644 --- a/src/Authoring/WinRT.SourceGenerator/ImmutableEquatableArray.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ImmutableEquatableArray.cs @@ -1,189 +1,189 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.CompilerServices; - -#nullable enable - -namespace WinRT.SourceGenerator -{ - - // Adapted from https://github.com/CommunityToolkit/dotnet/blob/main/src/CommunityToolkit.Mvvm.SourceGenerators/Helpers/EquatableArray%7BT%7D.cs - /// - /// An imutable, equatable array. This is equivalent to but with value equality support. - /// - /// The type of values in the array. - internal readonly struct EquatableArray : IEquatable>, IEnumerable - where T : IEquatable - { - /// - /// The underlying array. - /// - private readonly T[]? array; - - /// - /// Creates a new instance. - /// - /// The input to wrap. - public EquatableArray(ImmutableArray array) - { - this.array = Unsafe.As, T[]?>(ref array); - } - - /// - /// Gets a reference to an item at a specified position within the array. - /// - /// The index of the item to retrieve a reference to. - /// A reference to an item at a specified position within the array. - public ref readonly T this[int index] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref AsImmutableArray().ItemRef(index); - } - - /// - /// Gets a value indicating whether the current array is empty. - /// - public bool IsEmpty - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => AsImmutableArray().IsEmpty; - } - - /// - public bool Equals(EquatableArray array) - { - return AsSpan().SequenceEqual(array.AsSpan()); - } - - /// - public override bool Equals([NotNullWhen(true)] object? obj) - { - return obj is EquatableArray array && Equals(this, array); - } - - /// - public override int GetHashCode() - { - if (this.array is not T[] array) - { - return 0; - } - - int hashCode = 0; - - foreach (T item in array) - { - hashCode = unchecked((hashCode * (int)0xA5555529) + item.GetHashCode()); - } - - return hashCode; - } - - /// - /// Gets an instance from the current . - /// - /// The from the current . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ImmutableArray AsImmutableArray() - { - return Unsafe.As>(ref Unsafe.AsRef(in this.array)); - } - - /// - /// Creates an instance from a given . - /// - /// The input instance. - /// An instance from a given . - public static EquatableArray FromImmutableArray(ImmutableArray array) - { - return new(array); - } - - /// - /// Returns a wrapping the current items. - /// - /// A wrapping the current items. - public ReadOnlySpan AsSpan() - { - return AsImmutableArray().AsSpan(); - } - - /// - /// Copies the contents of this instance. to a mutable array. - /// - /// The newly instantiated array. - public T[] ToArray() - { - return AsImmutableArray().ToArray(); - } - - /// - /// Gets an value to traverse items in the current array. - /// - /// An value to traverse items in the current array. - public ImmutableArray.Enumerator GetEnumerator() - { - return AsImmutableArray().GetEnumerator(); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)AsImmutableArray()).GetEnumerator(); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)AsImmutableArray()).GetEnumerator(); - } - - /// - /// Implicitly converts an to . - /// - /// An instance from a given . - public static implicit operator EquatableArray(ImmutableArray array) - { - return FromImmutableArray(array); - } - - /// - /// Implicitly converts an to . - /// - /// An instance from a given . - public static implicit operator ImmutableArray(EquatableArray array) - { - return array.AsImmutableArray(); - } - - /// - /// Checks whether two values are the same. - /// - /// The first value. - /// The second value. - /// Whether and are equal. - public static bool operator ==(EquatableArray left, EquatableArray right) - { - return left.Equals(right); - } - - /// - /// Checks whether two values are not the same. - /// - /// The first value. - /// The second value. - /// Whether and are not equal. - public static bool operator !=(EquatableArray left, EquatableArray right) - { - return !left.Equals(right); - } - } -} +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; + +#nullable enable + +namespace WinRT.SourceGenerator +{ + + // Adapted from https://github.com/CommunityToolkit/dotnet/blob/main/src/CommunityToolkit.Mvvm.SourceGenerators/Helpers/EquatableArray%7BT%7D.cs + /// + /// An imutable, equatable array. This is equivalent to but with value equality support. + /// + /// The type of values in the array. + internal readonly struct EquatableArray : IEquatable>, IEnumerable + where T : IEquatable + { + /// + /// The underlying array. + /// + private readonly T[]? array; + + /// + /// Creates a new instance. + /// + /// The input to wrap. + public EquatableArray(ImmutableArray array) + { + this.array = Unsafe.As, T[]?>(ref array); + } + + /// + /// Gets a reference to an item at a specified position within the array. + /// + /// The index of the item to retrieve a reference to. + /// A reference to an item at a specified position within the array. + public ref readonly T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref AsImmutableArray().ItemRef(index); + } + + /// + /// Gets a value indicating whether the current array is empty. + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => AsImmutableArray().IsEmpty; + } + + /// + public bool Equals(EquatableArray array) + { + return AsSpan().SequenceEqual(array.AsSpan()); + } + + /// + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj is EquatableArray array && Equals(this, array); + } + + /// + public override int GetHashCode() + { + if (this.array is not T[] array) + { + return 0; + } + + int hashCode = 0; + + foreach (T item in array) + { + hashCode = unchecked((hashCode * (int)0xA5555529) + item.GetHashCode()); + } + + return hashCode; + } + + /// + /// Gets an instance from the current . + /// + /// The from the current . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ImmutableArray AsImmutableArray() + { + return Unsafe.As>(ref Unsafe.AsRef(in this.array)); + } + + /// + /// Creates an instance from a given . + /// + /// The input instance. + /// An instance from a given . + public static EquatableArray FromImmutableArray(ImmutableArray array) + { + return new(array); + } + + /// + /// Returns a wrapping the current items. + /// + /// A wrapping the current items. + public ReadOnlySpan AsSpan() + { + return AsImmutableArray().AsSpan(); + } + + /// + /// Copies the contents of this instance. to a mutable array. + /// + /// The newly instantiated array. + public T[] ToArray() + { + return AsImmutableArray().ToArray(); + } + + /// + /// Gets an value to traverse items in the current array. + /// + /// An value to traverse items in the current array. + public ImmutableArray.Enumerator GetEnumerator() + { + return AsImmutableArray().GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)AsImmutableArray()).GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)AsImmutableArray()).GetEnumerator(); + } + + /// + /// Implicitly converts an to . + /// + /// An instance from a given . + public static implicit operator EquatableArray(ImmutableArray array) + { + return FromImmutableArray(array); + } + + /// + /// Implicitly converts an to . + /// + /// An instance from a given . + public static implicit operator ImmutableArray(EquatableArray array) + { + return array.AsImmutableArray(); + } + + /// + /// Checks whether two values are the same. + /// + /// The first value. + /// The second value. + /// Whether and are equal. + public static bool operator ==(EquatableArray left, EquatableArray right) + { + return left.Equals(right); + } + + /// + /// Checks whether two values are not the same. + /// + /// The first value. + /// The second value. + /// Whether and are not equal. + public static bool operator !=(EquatableArray left, EquatableArray right) + { + return !left.Equals(right); + } + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/Logger.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Logger.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/Logger.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/Logger.cs diff --git a/src/Authoring/WinRT.SourceGenerator/MergeReferencedActivationFactoriesGenerator.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/MergeReferencedActivationFactoriesGenerator.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/MergeReferencedActivationFactoriesGenerator.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/MergeReferencedActivationFactoriesGenerator.cs diff --git a/src/Authoring/WinRT.SourceGenerator/Properties/launchSettings.json b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Properties/launchSettings.json similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/Properties/launchSettings.json rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/Properties/launchSettings.json diff --git a/src/Authoring/WinRT.SourceGenerator/RcwReflectionFallbackGenerator.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/RcwReflectionFallbackGenerator.cs similarity index 99% rename from src/Authoring/WinRT.SourceGenerator/RcwReflectionFallbackGenerator.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/RcwReflectionFallbackGenerator.cs index e0360602e..b481ca841 100644 --- a/src/Authoring/WinRT.SourceGenerator/RcwReflectionFallbackGenerator.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/RcwReflectionFallbackGenerator.cs @@ -56,8 +56,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) IncrementalValueProvider isGeneratorForceOptOut = context.AnalyzerConfigOptionsProvider.Select(static (options, token) => { return options.GetCsWinRTRcwFactoryFallbackGeneratorForceOptOut(); - }); - + }); + IncrementalValueProvider csWinRTAotWarningEnabled = context.AnalyzerConfigOptionsProvider.Select(static (options, token) => { return options.GetCsWinRTAotWarningLevel() >= 1; @@ -98,7 +98,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) ITypeSymbol attributeSymbol = compilation.GetTypeByMetadataName("System.Attribute")!; ITypeSymbol windowsRuntimeTypeAttributeSymbol = compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute")!; - ImmutableArray.Builder executableTypeNames = ImmutableArray.CreateBuilder(); + ImmutableArray.Builder executableTypeNames = ImmutableArray.CreateBuilder(); // Process all type symbols in the current assembly foreach (INamedTypeSymbol typeSymbol in VisitNamedTypeSymbolsExceptABI(assemblySymbol)) @@ -139,19 +139,19 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // These types are in the existing WinUI projection, but have been moved to the Windows SDK projection. // So if we see those, we want to ignore them. - if (typeName == "global::Windows.UI.Text.ContentLinkInfo" || - typeName == "global::Windows.UI.Text.RichEditTextDocument" || - typeName == "global::Windows.UI.Text.RichEditTextRange") - { - continue; + if (typeName == "global::Windows.UI.Text.ContentLinkInfo" || + typeName == "global::Windows.UI.Text.RichEditTextDocument" || + typeName == "global::Windows.UI.Text.RichEditTextRange") + { + continue; } // Check if we are able to resolve the type using GetTypeByMetadataName. If not, // it indicates there are multiple definitions of this type in the references // and us emitting a dependency on this type would cause compiler error. So emit // a warning instead. - bool hasMultipleDefinitions = compilation.GetTypeByMetadataName(GeneratorHelper.TrimGlobalFromTypeName(typeName)) is null; - executableTypeNames.Add(new RcwReflectionFallbackType(typeName, hasMultipleDefinitions)); + bool hasMultipleDefinitions = compilation.GetTypeByMetadataName(GeneratorHelper.TrimGlobalFromTypeName(typeName)) is null; + executableTypeNames.Add(new RcwReflectionFallbackType(typeName, hasMultipleDefinitions)); } token.ThrowIfCancellationRequested(); @@ -203,19 +203,19 @@ internal static class RcwFallbackInitializer { // If there are multiple definitions of the type, emitting a dependency would result in a compiler error. // So instead, emit a diagnostic for it. - if (projectedTypeName.HasMultipleDefinitions) - { - var diagnosticDescriptor = value.csWinRTAotWarningEnabled ? - WinRTRules.ClassNotAotCompatibleOldProjectionMultipleInstancesWarning : WinRTRules.ClassNotAotCompatibleOldProjectionMultipleInstancesInfo; - // We have no location to emit the diagnostic as this is just a reference we detect. - context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, null, GeneratorHelper.TrimGlobalFromTypeName(projectedTypeName.TypeName))); + if (projectedTypeName.HasMultipleDefinitions) + { + var diagnosticDescriptor = value.csWinRTAotWarningEnabled ? + WinRTRules.ClassNotAotCompatibleOldProjectionMultipleInstancesWarning : WinRTRules.ClassNotAotCompatibleOldProjectionMultipleInstancesInfo; + // We have no location to emit the diagnostic as this is just a reference we detect. + context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, null, GeneratorHelper.TrimGlobalFromTypeName(projectedTypeName.TypeName))); } - else - { - emittedDynamicDependency = true; - builder.Append(" [DynamicDependency(DynamicallyAccessedMemberTypes.NonPublicConstructors, typeof("); - builder.Append(projectedTypeName.TypeName); - builder.AppendLine("))]"); + else + { + emittedDynamicDependency = true; + builder.Append(" [DynamicDependency(DynamicallyAccessedMemberTypes.NonPublicConstructors, typeof("); + builder.Append(projectedTypeName.TypeName); + builder.AppendLine("))]"); } } @@ -227,9 +227,9 @@ public static void InitializeRcwFallback() } """); - if (emittedDynamicDependency) - { - context.AddSource("RcwFallbackInitializer.g.cs", builder.ToString()); + if (emittedDynamicDependency) + { + context.AddSource("RcwFallbackInitializer.g.cs", builder.ToString()); } }); } @@ -333,7 +333,7 @@ public bool Equals(EquatablePortableExecutableReference other) return other.Reference.GetMetadataId() == Reference.GetMetadataId(); } - } - - internal readonly record struct RcwReflectionFallbackType(string TypeName, bool HasMultipleDefinitions); + } + + internal readonly record struct RcwReflectionFallbackType(string TypeName, bool HasMultipleDefinitions); } diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/de-DE/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/de-DE/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/de-DE/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/de-DE/CsWinRTDiagnosticStrings.resx index 9172e31f8..bf5675041 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/de-DE/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/de-DE/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Als InAttribute oder OutAttribute markierter Array-Parameter - - - Die Methode '{0}' hat einen Parameter '{1}', der ein Array ist und entweder ein System.Runtime.InteropServices.InAttribute oder ein System.Runtime.InteropServices.OutAttribute aufweist. - - - In Windows-Runtime müssen Arrayparameter entweder ReadOnlyArray oder WriteOnlyArray aufweisen. - - - Entfernen Sie diese Attribute, oder ersetzen Sie sie bei Bedarf durch das entsprechende Windows-Runtime-Attribut. - - - Array-Parameter mit „out“ und ReadOnlyArray gekennzeichnet - - - Die Methode '{0}' hat einen Ausgabeparameter '{1}', der ein Array ist, das jedoch das Attribut ReadOnlyArray aufweist. - - - In der Windows-Runtime sind die Inhalte von Ausgabearrays beschreibbar. Entfernen Sie das Attribut aus '{1}'. - - - Array-Parameter, der sowohl mit ReadOnlyArray als auch mit WriteOnlyArray gekennzeichnet ist - - - Die Methode '{0}' hat einen Parameter '{1}', der ein Array ist und sowohl ReadOnlyArray als auch WriteOnlyArray aufweist. - - - In der Windows-Runtime müssen die Parameter des Inhaltsarrays entweder lesbar oder beschreibbar sein. Entfernen Sie eines der Attribute aus '{1}'. - - - Arrayparameter nicht als ReadOnlyArray- oder WriteOnlyArray-Methode markiert - - - Die Methode '{0}' hat einen Parameter '{1}', bei dem es sich um ein Array handelt. - - - In Windows-Runtime muss der Inhalt von Array-Parametern entweder lesbar oder schreibbar sein; bitte wenden Sie entweder „ReadOnlyArray“ oder „WriteOnlyArray“ auf „{1}“ an. - - - Klassenkonstruktorregel - - - Klassen dürfen nicht mehrere Konstruktoren derselben Stelligkeit in der Windows-Runtime aufweisen. Die Klasse {0} hat mehrere {1}-Stelligkeitskonstruktoren. - - - Der Namespace ist vom Hauptnamespace (winmd) getrennt. - - - Ein öffentlicher Typ hat einen Namespace ('{1}'), der kein gemeinsames Präfix mit anderen Namespaces ('{0}') gemeinsam hat. - {1} and {0} will be some user-defined keyword - - - Alle Typen in einer Windows-Metadatendatei müssen in einem Unter-Namensraum des Namensraums vorhanden sein, der durch den Dateinamen impliziert wird. - "sub namespace" means a namespace defined within another namespace - - - Klasse (oder Schnittstelle) ist generisch - - - Typ {0} ist generisch, Windows-Runtime-Typen dürfen nicht generisch sein. - {0} will be some user-defined keyword - - - Es wurde eine Arraysignatur mit gezacktem Array gefunden. Dies ist kein gültiger WinRT-Typ. - - - Die Methode{0} hat ein verschachteltes Array vom Typ{1} in ihrer Signatur. Arrays in der Windows-Runtime-Methodensignatur können nicht geschachtelt werden. - - - Array-Signatur mit mehrdimensionalem Array gefunden, das kein gültiger Windows-Runtime-Typ ist - - - Die Methode „{0}“ weist ein mehrdimensionales Array vom Typ „{1}“ in ihrer Signatur auf. Arrays in Windows-Runtime-Methodensignaturen müssen eindimensional sein. - - - Es sollte nur eine Überladung als Standard festgelegt werden. - - - In der Klasse {2}: Mehrere {0}-parameter-Überladungen von „{1}“ sind mit Windows.Foundation.Metadata.DefaultOverloadAttribute versehen. - - - Das Attribut kann nur auf eine Überladung der Methode angewendet werden. - - - Namespace-Namen dürfen sich nicht nur durch Groß- und Kleinschreibung unterscheiden. - - - Es wurden mehrere Namespaces mit dem Namen "'{0}';" gefunden. Namespacenamen dürfen sich nicht nur in der Windows-Runtime - {0} will be some user-defined keyword - - - Mehrere Überladungen ohne DefaultOverload-Attribut gesehen - - - In Klasse {2}: Für die {0}-parameter-Überladungen von {1} muss genau eine Methode als Standardüberladung angegeben sein, indem sie mit Windows.Foundation.Metadata.DefaultOverloadAttribute decodiert wird. - - - Parameter (kein Arraytyp) mit InAttribute oder OutAttribute markiert - - - Die Methode „{0}“ hat den Parameter „{1}“ mit einem System.Runtime.InteropServices.InAttribute oder System.Runtime.InteropServices.OutAttribute.Windows-Runtime unterstützt das Markieren von Parametern mit System.Runtime.InteropServices.InAttribute oder System.Runtime.InteropServices.OutAttribute nicht. - - - Entfernen Sie ggf. System.Runtime.InteropServices.InAttribute, und ersetzen Sie stattdessen System.Runtime.InteropServices.OutAttribute durch den out-Modifizierer. - - - Nicht-Arrayparameter, der mit ReadOnlyArray oder WriteOnlyArray markiert ist - - - Die Methode '{0}' hat einen Parameter '{1}', der kein Array ist und entweder ein ReadOnlyArray-Attribut oder ein WriteOnlyArray-Attribut aufweist. - - - Windows-Runtime unterstützt nicht das Markieren von Nicht-Arrayparametern mit ReadOnlyArray oder WriteOnlyArray. - - - Ungültige übernommene Schnittstelle - - - Windows-Runtime Komponententyp kann {0} die Schnittstelle nicht {1} implementieren, da die Schnittstelle keine gültige Windows-Runtime Schnittstelle ist. - - - Es wurden keine öffentlichen Typen definiert. - - - Komponenten für Windows-Runtime müssen mindestens einen öffentlichen Typ aufweisen. - - - Operatorüberladung verfügbar gemacht - - - {0} ist eine Operatorüberladung, verwaltete Typen können keine Operatorüberladungen in Windows-Runtime bereitstellen. - - - Parameter-benannte Werte-Regel - - - Der Parametername{1} in der Methode{0} ist derselbe wie der Parametername des Rückgabewerts, der in der generierten C#/WinRT-Interop verwendet wird; verwenden Sie einen anderen Parameternamen. - - - Die Eigenschaft muss über einen öffentlichen Getter verfügen. - - - Die Eigenschaft „{0}“ verfügt über keine öffentliche Getter-Methode. Windows-Runtime unterstützt keine reinen Setter-Eigenschaften. - {0} will be some user-defined keyword - - - Als Verweis übergebener Parameter - - - Die Methode '{0}' hat einen Parameter, '{1}' als "ref" markiert ist; Verweisparameter sind in Windows-Runtime nicht zulässig. - - - Const-Feld in struct - - - Die Struktur {0} weist ein konstantes Feld auf. Konstanten können nur für Windows-Runtime Enumerationen verwendet werden. - - - Ungültiges Feld in der Struktur - - - Die Struktur {0} hat ein Feld vom Typ {1}; {1} ist kein gültiger Windows-Runtime Feldtyp. - - - Jedes Feld in einer Windows-Runtime-Struktur kann nur UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum oder selbst eine Struktur sein. - - - Privates Feld in der Struktur - - - Die Struktur {0} weist ein nicht öffentliches Feld auf. Alle Felder müssen für Windows-Runtime-Strukturen öffentlich sein. - - - Leere Strukturregel - - - Struktur {0} enthält keine öffentlichen Felder. Windows-Runtime-Strukturen müssen mindestens ein öffentliches Feld enthalten. - - - Die Klasse implementiert eine Schnittstelle falsch. - - - Die '{0}' implementiert die Schnittstelle '{1}' nicht ordnungsgemäß, da '{2}' fehlt oder nicht öffentlich ist. - - - Die Klasse ist nicht versiegelt. - - - Das Exportieren nicht versiegelter Typen wird in CsWinRT nicht unterstützt. Markieren Sie den Typ {0} als versiegelt. - {0} will be some user-defined keyword - - - Verfügbarmachen eines nicht unterstützten Typs - - - Der Member '{0}' weist den Typ '{1}' in der Signatur auf. - {0} and {1} will be user-defined keywords - - - Der Typ „{1}“ ist kein gültiger Windows-Runtime-Typ. - {1} will be some user-defined keyword - - - Der Typ (oder seine generischen Parameter) implementiert jedoch Schnittstellen, die gültige Windows-Runtime-Typen sind. - - - Erwägen Sie, den Typ „{1}“ in der Member-Signatur in einen der folgenden Typen aus System.Collections.Generic zu ändern: {2}. - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Als InAttribute oder OutAttribute markierter Array-Parameter + + + Die Methode '{0}' hat einen Parameter '{1}', der ein Array ist und entweder ein System.Runtime.InteropServices.InAttribute oder ein System.Runtime.InteropServices.OutAttribute aufweist. + + + In Windows-Runtime müssen Arrayparameter entweder ReadOnlyArray oder WriteOnlyArray aufweisen. + + + Entfernen Sie diese Attribute, oder ersetzen Sie sie bei Bedarf durch das entsprechende Windows-Runtime-Attribut. + + + Array-Parameter mit „out“ und ReadOnlyArray gekennzeichnet + + + Die Methode '{0}' hat einen Ausgabeparameter '{1}', der ein Array ist, das jedoch das Attribut ReadOnlyArray aufweist. + + + In der Windows-Runtime sind die Inhalte von Ausgabearrays beschreibbar. Entfernen Sie das Attribut aus '{1}'. + + + Array-Parameter, der sowohl mit ReadOnlyArray als auch mit WriteOnlyArray gekennzeichnet ist + + + Die Methode '{0}' hat einen Parameter '{1}', der ein Array ist und sowohl ReadOnlyArray als auch WriteOnlyArray aufweist. + + + In der Windows-Runtime müssen die Parameter des Inhaltsarrays entweder lesbar oder beschreibbar sein. Entfernen Sie eines der Attribute aus '{1}'. + + + Arrayparameter nicht als ReadOnlyArray- oder WriteOnlyArray-Methode markiert + + + Die Methode '{0}' hat einen Parameter '{1}', bei dem es sich um ein Array handelt. + + + In Windows-Runtime muss der Inhalt von Array-Parametern entweder lesbar oder schreibbar sein; bitte wenden Sie entweder „ReadOnlyArray“ oder „WriteOnlyArray“ auf „{1}“ an. + + + Klassenkonstruktorregel + + + Klassen dürfen nicht mehrere Konstruktoren derselben Stelligkeit in der Windows-Runtime aufweisen. Die Klasse {0} hat mehrere {1}-Stelligkeitskonstruktoren. + + + Der Namespace ist vom Hauptnamespace (winmd) getrennt. + + + Ein öffentlicher Typ hat einen Namespace ('{1}'), der kein gemeinsames Präfix mit anderen Namespaces ('{0}') gemeinsam hat. + {1} and {0} will be some user-defined keyword + + + Alle Typen in einer Windows-Metadatendatei müssen in einem Unter-Namensraum des Namensraums vorhanden sein, der durch den Dateinamen impliziert wird. + "sub namespace" means a namespace defined within another namespace + + + Klasse (oder Schnittstelle) ist generisch + + + Typ {0} ist generisch, Windows-Runtime-Typen dürfen nicht generisch sein. + {0} will be some user-defined keyword + + + Es wurde eine Arraysignatur mit gezacktem Array gefunden. Dies ist kein gültiger WinRT-Typ. + + + Die Methode{0} hat ein verschachteltes Array vom Typ{1} in ihrer Signatur. Arrays in der Windows-Runtime-Methodensignatur können nicht geschachtelt werden. + + + Array-Signatur mit mehrdimensionalem Array gefunden, das kein gültiger Windows-Runtime-Typ ist + + + Die Methode „{0}“ weist ein mehrdimensionales Array vom Typ „{1}“ in ihrer Signatur auf. Arrays in Windows-Runtime-Methodensignaturen müssen eindimensional sein. + + + Es sollte nur eine Überladung als Standard festgelegt werden. + + + In der Klasse {2}: Mehrere {0}-parameter-Überladungen von „{1}“ sind mit Windows.Foundation.Metadata.DefaultOverloadAttribute versehen. + + + Das Attribut kann nur auf eine Überladung der Methode angewendet werden. + + + Namespace-Namen dürfen sich nicht nur durch Groß- und Kleinschreibung unterscheiden. + + + Es wurden mehrere Namespaces mit dem Namen "'{0}';" gefunden. Namespacenamen dürfen sich nicht nur in der Windows-Runtime + {0} will be some user-defined keyword + + + Mehrere Überladungen ohne DefaultOverload-Attribut gesehen + + + In Klasse {2}: Für die {0}-parameter-Überladungen von {1} muss genau eine Methode als Standardüberladung angegeben sein, indem sie mit Windows.Foundation.Metadata.DefaultOverloadAttribute decodiert wird. + + + Parameter (kein Arraytyp) mit InAttribute oder OutAttribute markiert + + + Die Methode „{0}“ hat den Parameter „{1}“ mit einem System.Runtime.InteropServices.InAttribute oder System.Runtime.InteropServices.OutAttribute.Windows-Runtime unterstützt das Markieren von Parametern mit System.Runtime.InteropServices.InAttribute oder System.Runtime.InteropServices.OutAttribute nicht. + + + Entfernen Sie ggf. System.Runtime.InteropServices.InAttribute, und ersetzen Sie stattdessen System.Runtime.InteropServices.OutAttribute durch den out-Modifizierer. + + + Nicht-Arrayparameter, der mit ReadOnlyArray oder WriteOnlyArray markiert ist + + + Die Methode '{0}' hat einen Parameter '{1}', der kein Array ist und entweder ein ReadOnlyArray-Attribut oder ein WriteOnlyArray-Attribut aufweist. + + + Windows-Runtime unterstützt nicht das Markieren von Nicht-Arrayparametern mit ReadOnlyArray oder WriteOnlyArray. + + + Ungültige übernommene Schnittstelle + + + Windows-Runtime Komponententyp kann {0} die Schnittstelle nicht {1} implementieren, da die Schnittstelle keine gültige Windows-Runtime Schnittstelle ist. + + + Es wurden keine öffentlichen Typen definiert. + + + Komponenten für Windows-Runtime müssen mindestens einen öffentlichen Typ aufweisen. + + + Operatorüberladung verfügbar gemacht + + + {0} ist eine Operatorüberladung, verwaltete Typen können keine Operatorüberladungen in Windows-Runtime bereitstellen. + + + Parameter-benannte Werte-Regel + + + Der Parametername{1} in der Methode{0} ist derselbe wie der Parametername des Rückgabewerts, der in der generierten C#/WinRT-Interop verwendet wird; verwenden Sie einen anderen Parameternamen. + + + Die Eigenschaft muss über einen öffentlichen Getter verfügen. + + + Die Eigenschaft „{0}“ verfügt über keine öffentliche Getter-Methode. Windows-Runtime unterstützt keine reinen Setter-Eigenschaften. + {0} will be some user-defined keyword + + + Als Verweis übergebener Parameter + + + Die Methode '{0}' hat einen Parameter, '{1}' als "ref" markiert ist; Verweisparameter sind in Windows-Runtime nicht zulässig. + + + Const-Feld in struct + + + Die Struktur {0} weist ein konstantes Feld auf. Konstanten können nur für Windows-Runtime Enumerationen verwendet werden. + + + Ungültiges Feld in der Struktur + + + Die Struktur {0} hat ein Feld vom Typ {1}; {1} ist kein gültiger Windows-Runtime Feldtyp. + + + Jedes Feld in einer Windows-Runtime-Struktur kann nur UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum oder selbst eine Struktur sein. + + + Privates Feld in der Struktur + + + Die Struktur {0} weist ein nicht öffentliches Feld auf. Alle Felder müssen für Windows-Runtime-Strukturen öffentlich sein. + + + Leere Strukturregel + + + Struktur {0} enthält keine öffentlichen Felder. Windows-Runtime-Strukturen müssen mindestens ein öffentliches Feld enthalten. + + + Die Klasse implementiert eine Schnittstelle falsch. + + + Die '{0}' implementiert die Schnittstelle '{1}' nicht ordnungsgemäß, da '{2}' fehlt oder nicht öffentlich ist. + + + Die Klasse ist nicht versiegelt. + + + Das Exportieren nicht versiegelter Typen wird in CsWinRT nicht unterstützt. Markieren Sie den Typ {0} als versiegelt. + {0} will be some user-defined keyword + + + Verfügbarmachen eines nicht unterstützten Typs + + + Der Member '{0}' weist den Typ '{1}' in der Signatur auf. + {0} and {1} will be user-defined keywords + + + Der Typ „{1}“ ist kein gültiger Windows-Runtime-Typ. + {1} will be some user-defined keyword + + + Der Typ (oder seine generischen Parameter) implementiert jedoch Schnittstellen, die gültige Windows-Runtime-Typen sind. + + + Erwägen Sie, den Typ „{1}“ in der Member-Signatur in einen der folgenden Typen aus System.Collections.Generic zu ändern: {2}. + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/es-ES/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/es-ES/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/es-ES/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/es-ES/CsWinRTDiagnosticStrings.resx index e6f3106f7..54e82524c 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/es-ES/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/es-ES/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Parámetro de matriz marcado como InAttribute o OutAttribute - - - El método '{0}' tiene un parámetro '{1}' que es una matriz y que tiene System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute. - - - En el Windows Runtime, los parámetros de matriz deben tener ReadOnlyArray o WriteOnlyArray. - - - Quite estos atributos o reemplácelos por el atributo de Windows Runtime adecuado si es necesario. - - - Parámetro de matriz marcado como `out` y ReadOnlyArray - - - El método '{0}' tiene un parámetro de salida '{1}' que es una matriz, pero que tiene el atributo ReadOnlyArray. - - - En el Windows Runtime, se puede escribir en el contenido de las matrices de salida. Quite el atributo de '{1}'. - - - Parámetro de matriz marcado como ReadOnlyArray y WriteOnlyArray - - - El método '{0}' tiene un parámetro '{1}' que es una matriz y que tiene ReadOnlyArray y WriteOnlyArray. - - - En el Windows Runtime, los parámetros de la matriz de contenido deben ser legibles o grabables. Quite uno de los atributos de '{1}'. - - - Parámetro de matriz no marcado como ReadOnlyArray o WriteOnlyArray - - - El método '{0}' tiene un parámetro '{1}' que es una matriz. - - - En el Windows Runtime, el contenido de los parámetros de matriz debe ser legible o grabable; aplique ReadOnlyArray o WriteOnlyArray a '{1}'. - - - Regla de constructor de clase - - - Las clases no pueden tener varios constructores de la misma aridad en el Windows Runtime, la clase {0} tiene varios constructores de aridad {1} - - - El espacio de nombres es independiente del espacio de nombres principal (winmd) - - - Un tipo público tiene un espacio de nombres ('{1}') que no comparte ningún prefijo común con otros espacios de nombres ('{0}'). - {1} and {0} will be some user-defined keyword - - - Todos los tipos de un archivo de metadatos de Windows deben existir en un subes namespace del espacio de nombres que implica el nombre de archivo. - "sub namespace" means a namespace defined within another namespace - - - La clase (o interfaz) es genérica - - - El tipo {0} es genérico, los tipos de Windows Runtime no pueden ser genéricos - {0} will be some user-defined keyword - - - Se encontró una firma de matriz con matriz escalonada, que no es un tipo WinRT válido - - - El método {0} tiene una matriz anidada de tipo {1} en su signatura; las matrices de Windows Runtime signatura de método no se pueden anidar - - - Se encontró una firma de matriz con una matriz multidimensional, que no es un tipo de Windows Runtime válido - - - El método '{0}' tiene una matriz multidimensional de tipo '{1}" en su firma; las matrices de métodos de firma de Windows Runtime deben ser unidimensionales - - - Solo se debe designar una sobrecarga como predeterminada - - - En la clase {2}: varias sobrecargas -parameter {0} de '{1}' se decoran con Windows.Foundation.Metadata.DefaultOverloadAttribute. - - - El atributo solo se puede aplicar a una sobrecarga del método. - - - Los nombres de espacio de nombres no pueden diferir solo en mayúsculas y minúsculas - - - Se encontraron varios espacios de nombres con el nombre '{0}'; los nombres de espacio de nombres no pueden diferir solo por mayúsculas y minúsculas en el Windows Runtime - {0} will be some user-defined keyword - - - Se han detectado varias sobrecargas sin el atributo DefaultOverload - - - En la clase {2}: las sobrecargas -parameter {0} de {1} deben tener exactamente un método especificado como sobrecarga predeterminada decorando con Windows.Foundation.Metadata.DefaultOverloadAttribute - - - Parámetro (no tipo de matriz) marcado como InAttribute o OutAttribute - - - El método '{0}' tiene un parámetro '{1}' con System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute.Windows Runtime no admite marcar parámetros con System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute. - - - Considere la posibilidad de quitar System.Runtime.InteropServices.InAttribute y reemplace System.Runtime.InteropServices.OutAttribute por el modificador 'out'. - - - Parámetro que no es de matriz marcado con ReadOnlyArray o WriteOnlyArray - - - El método '{0}' tiene un parámetro '{1}' que no es una matriz y que tiene un atributo ReadOnlyArray o un atributo WriteOnlyArray. - - - Windows Runtime no admite el marcado de parámetros que no son de matriz con ReadOnlyArray o WriteOnlyArray. - - - Interfaz heredada no válida - - - Windows Runtime tipo de componente {0} no puede implementar {1} de interfaz, ya que la interfaz no es una interfaz Windows Runtime válida - - - No hay tipos públicos definidos - - - Windows Runtime componentes deben tener al menos un tipo público - - - Sobrecarga de operador expuesta - - - {0} es una sobrecarga de operador, los tipos administrados no pueden exponer sobrecargas de operador en el Windows Runtime - - - Regla de valor con nombre de parámetro - - - El nombre de parámetro {1} en el método {0} es el mismo que el nombre del parámetro de valor devuelto usado en la interoperabilidad C#/WinRT generada; usar un nombre de parámetro diferente - - - La propiedad debe tener captador público - - - La propiedad '{0}' no tiene un método getter público. Windows Runtime no admite propiedades de solo establecedor. - {0} will be some user-defined keyword - - - Parámetro pasado por referencia - - - El método '{0}' tiene el parámetro '{1}' marcado como 'ref'; no se permiten parámetros de referencia en Windows Runtime - - - Campo Const en struct - - - La estructura {0} tiene un campo const: las constantes solo pueden aparecer en enumeraciones de Windows Runtime. - - - Campo no válido en struct - - - La estructura {0} tiene un campo de tipo {1}; {1} no es un tipo de campo Windows Runtime válido. - - - Cada campo de una estructura de Windows Runtime solo puede ser UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum o, a su vez, una estructura. - - - Campo privado en struct - - - La estructura {0} tiene un campo no público. Todos los campos deben ser públicos para las estructuras Windows Runtime. - - - Regla de estructura vacía - - - La estructura {0} no contiene campos públicos. Windows Runtime estructuras deben contener al menos un campo público. - - - La clase implementa incorrectamente una interfaz - - - La clase '{0}' no implementa correctamente la interfaz '{1}' porque falta el miembro '{2}' o no es público - - - La clase no está cerrada - - - No se admite la exportación de tipos no cerrados en CsWinRT. Marque el tipo {0} como cerrado - {0} will be some user-defined keyword - - - Exponiendo el tipo no admitido - - - El miembro '{0}' tiene el tipo '{1}' en su signatura. - {0} and {1} will be user-defined keywords - - - El tipo '{1}' no es un tipo Windows Runtime válido. - {1} will be some user-defined keyword - - - Sin embargo, el tipo (o sus parámetros genéricos) implementan interfaces que son tipos de Windows Runtime válidos. - - - Considere la posibilidad de cambiar el tipo '{1} de la firma de miembro a uno de los siguientes tipos de System.Collections.Generic: {2}. - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Parámetro de matriz marcado como InAttribute o OutAttribute + + + El método '{0}' tiene un parámetro '{1}' que es una matriz y que tiene System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute. + + + En el Windows Runtime, los parámetros de matriz deben tener ReadOnlyArray o WriteOnlyArray. + + + Quite estos atributos o reemplácelos por el atributo de Windows Runtime adecuado si es necesario. + + + Parámetro de matriz marcado como `out` y ReadOnlyArray + + + El método '{0}' tiene un parámetro de salida '{1}' que es una matriz, pero que tiene el atributo ReadOnlyArray. + + + En el Windows Runtime, se puede escribir en el contenido de las matrices de salida. Quite el atributo de '{1}'. + + + Parámetro de matriz marcado como ReadOnlyArray y WriteOnlyArray + + + El método '{0}' tiene un parámetro '{1}' que es una matriz y que tiene ReadOnlyArray y WriteOnlyArray. + + + En el Windows Runtime, los parámetros de la matriz de contenido deben ser legibles o grabables. Quite uno de los atributos de '{1}'. + + + Parámetro de matriz no marcado como ReadOnlyArray o WriteOnlyArray + + + El método '{0}' tiene un parámetro '{1}' que es una matriz. + + + En el Windows Runtime, el contenido de los parámetros de matriz debe ser legible o grabable; aplique ReadOnlyArray o WriteOnlyArray a '{1}'. + + + Regla de constructor de clase + + + Las clases no pueden tener varios constructores de la misma aridad en el Windows Runtime, la clase {0} tiene varios constructores de aridad {1} + + + El espacio de nombres es independiente del espacio de nombres principal (winmd) + + + Un tipo público tiene un espacio de nombres ('{1}') que no comparte ningún prefijo común con otros espacios de nombres ('{0}'). + {1} and {0} will be some user-defined keyword + + + Todos los tipos de un archivo de metadatos de Windows deben existir en un subes namespace del espacio de nombres que implica el nombre de archivo. + "sub namespace" means a namespace defined within another namespace + + + La clase (o interfaz) es genérica + + + El tipo {0} es genérico, los tipos de Windows Runtime no pueden ser genéricos + {0} will be some user-defined keyword + + + Se encontró una firma de matriz con matriz escalonada, que no es un tipo WinRT válido + + + El método {0} tiene una matriz anidada de tipo {1} en su signatura; las matrices de Windows Runtime signatura de método no se pueden anidar + + + Se encontró una firma de matriz con una matriz multidimensional, que no es un tipo de Windows Runtime válido + + + El método '{0}' tiene una matriz multidimensional de tipo '{1}" en su firma; las matrices de métodos de firma de Windows Runtime deben ser unidimensionales + + + Solo se debe designar una sobrecarga como predeterminada + + + En la clase {2}: varias sobrecargas -parameter {0} de '{1}' se decoran con Windows.Foundation.Metadata.DefaultOverloadAttribute. + + + El atributo solo se puede aplicar a una sobrecarga del método. + + + Los nombres de espacio de nombres no pueden diferir solo en mayúsculas y minúsculas + + + Se encontraron varios espacios de nombres con el nombre '{0}'; los nombres de espacio de nombres no pueden diferir solo por mayúsculas y minúsculas en el Windows Runtime + {0} will be some user-defined keyword + + + Se han detectado varias sobrecargas sin el atributo DefaultOverload + + + En la clase {2}: las sobrecargas -parameter {0} de {1} deben tener exactamente un método especificado como sobrecarga predeterminada decorando con Windows.Foundation.Metadata.DefaultOverloadAttribute + + + Parámetro (no tipo de matriz) marcado como InAttribute o OutAttribute + + + El método '{0}' tiene un parámetro '{1}' con System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute.Windows Runtime no admite marcar parámetros con System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute. + + + Considere la posibilidad de quitar System.Runtime.InteropServices.InAttribute y reemplace System.Runtime.InteropServices.OutAttribute por el modificador 'out'. + + + Parámetro que no es de matriz marcado con ReadOnlyArray o WriteOnlyArray + + + El método '{0}' tiene un parámetro '{1}' que no es una matriz y que tiene un atributo ReadOnlyArray o un atributo WriteOnlyArray. + + + Windows Runtime no admite el marcado de parámetros que no son de matriz con ReadOnlyArray o WriteOnlyArray. + + + Interfaz heredada no válida + + + Windows Runtime tipo de componente {0} no puede implementar {1} de interfaz, ya que la interfaz no es una interfaz Windows Runtime válida + + + No hay tipos públicos definidos + + + Windows Runtime componentes deben tener al menos un tipo público + + + Sobrecarga de operador expuesta + + + {0} es una sobrecarga de operador, los tipos administrados no pueden exponer sobrecargas de operador en el Windows Runtime + + + Regla de valor con nombre de parámetro + + + El nombre de parámetro {1} en el método {0} es el mismo que el nombre del parámetro de valor devuelto usado en la interoperabilidad C#/WinRT generada; usar un nombre de parámetro diferente + + + La propiedad debe tener captador público + + + La propiedad '{0}' no tiene un método getter público. Windows Runtime no admite propiedades de solo establecedor. + {0} will be some user-defined keyword + + + Parámetro pasado por referencia + + + El método '{0}' tiene el parámetro '{1}' marcado como 'ref'; no se permiten parámetros de referencia en Windows Runtime + + + Campo Const en struct + + + La estructura {0} tiene un campo const: las constantes solo pueden aparecer en enumeraciones de Windows Runtime. + + + Campo no válido en struct + + + La estructura {0} tiene un campo de tipo {1}; {1} no es un tipo de campo Windows Runtime válido. + + + Cada campo de una estructura de Windows Runtime solo puede ser UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum o, a su vez, una estructura. + + + Campo privado en struct + + + La estructura {0} tiene un campo no público. Todos los campos deben ser públicos para las estructuras Windows Runtime. + + + Regla de estructura vacía + + + La estructura {0} no contiene campos públicos. Windows Runtime estructuras deben contener al menos un campo público. + + + La clase implementa incorrectamente una interfaz + + + La clase '{0}' no implementa correctamente la interfaz '{1}' porque falta el miembro '{2}' o no es público + + + La clase no está cerrada + + + No se admite la exportación de tipos no cerrados en CsWinRT. Marque el tipo {0} como cerrado + {0} will be some user-defined keyword + + + Exponiendo el tipo no admitido + + + El miembro '{0}' tiene el tipo '{1}' en su signatura. + {0} and {1} will be user-defined keywords + + + El tipo '{1}' no es un tipo Windows Runtime válido. + {1} will be some user-defined keyword + + + Sin embargo, el tipo (o sus parámetros genéricos) implementan interfaces que son tipos de Windows Runtime válidos. + + + Considere la posibilidad de cambiar el tipo '{1} de la firma de miembro a uno de los siguientes tipos de System.Collections.Generic: {2}. + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/fr-FR/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/fr-FR/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/fr-FR/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/fr-FR/CsWinRTDiagnosticStrings.resx index cae843779..9b830d509 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/fr-FR/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/fr-FR/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Paramètre de tableau marqué InAttribute ou OutAttribute - - - La méthode '{0}' a un paramètre '{1}' qui est un tableau et qui a un System.Runtime.InteropServices.InAttribute ou system.Runtime.InteropServices.OutAttribute. - - - Dans le Windows Runtime, les paramètres de tableau doivent avoir ReadOnlyArray ou WriteOnlyArray. - - - Supprimez ces attributs ou remplacez-les par l’attribut Windows Runtime approprié si nécessaire. - - - Paramètre de tableau marqué `out` et ReadOnlyArray - - - La méthode '{0}' a un paramètre de sortie '{1}' qui est un tableau, mais qui a l’attribut ReadOnlyArray. - - - Dans le Windows Runtime, le contenu des tableaux de sortie est accessible en écriture. Supprimez l’attribut de '{1}'. - - - Paramètre de tableau marqué à la fois comme ReadOnlyArray et WriteOnlyArray - - - La méthode '{0}' a un paramètre '{1}' qui est un tableau et qui a ReadOnlyArray et WriteOnlyArray. - - - Dans le Windows Runtime, les paramètres du tableau de contenu doivent être lisibles ou accessibles en écriture. Supprimez l’un des attributs de '{1}'. - - - Paramètre de tableau non marqué avec ReadOnlyArray ou WriteOnlyArray - - - La méthode '{0}' a un paramètre '{1}' qui est un tableau. - - - Dans le Windows Runtime, le contenu des paramètres de tableau doit être lisible ou accessible en écriture ; appliquez ReadOnlyArray ou WriteOnlyArray à '{1}'. - - - Règle de constructeur de classe - - - Les classes ne peuvent pas avoir plusieurs constructeurs de la même arité dans le Windows Runtime, la classe {0} a plusieurs constructeurs d’arité {1} - - - L’espace de noms est disjoint de l’espace de noms principal (winmd) - - - Un type public a un espace de noms ('{1}') qui ne partage aucun préfixe commun avec d’autres espaces de noms ('{0}'). - {1} and {0} will be some user-defined keyword - - - Tous les types d’un fichier de métadonnées Windows doivent exister dans un sous-espace de noms de l’espace de noms qui est impliqué par le nom de fichier. - "sub namespace" means a namespace defined within another namespace - - - La classe (ou l’interface) est générique - - - Le type {0} est générique, les types Windows Runtime ne peuvent pas être génériques - {0} will be some user-defined keyword - - - Signature de tableau trouvée avec un tableau en escalier, qui n’est pas un type WinRT valide - - - La méthode {0} a un tableau imbriqué de type {1} dans sa signature ; les tableaux dans Windows Runtime signature de méthode ne peuvent pas être imbriqués - - - Signature de tableau trouvée avec un tableau multidimensionnel, qui n’est pas un type Windows Runtime valide - - - La méthode « {0} » possède un tableau multidimensionnel de type « {1} » dans sa signature ; les tableaux dans les signatures de méthode Windows Runtime doivent être unidimensionnels - - - Une seule surcharge doit être désignée par défaut - - - Dans la classe {2} : plusieurs surcharges de {0}-paramètre de « {1} » sont décorées avec Windows.Foundation.Metadata.DefaultOverloadAttribute. - - - L’attribut ne peut être appliqué qu’à une seule surcharge de la méthode. - - - Les noms d’espaces de noms ne peuvent pas différer uniquement par la casse - - - Plusieurs espaces de noms portant le nom '{0}'; les noms d’espace de noms ne peuvent pas différer uniquement par la casse dans le Windows Runtime - {0} will be some user-defined keyword - - - Surcharges multiples rencontrées sans attribut DefaultOverload - - - Dans la classe {2} : les surcharges de {0}-paramètre de {1} doivent avoir exactement une méthode spécifiée comme surcharge par défaut en la décorant avec Windows.Foundation.Metadata.DefaultOverloadAttribute - - - Paramètre (non de type de tableau) marqué InAttribute ou OutAttribute - - - La méthode « {0} » a un paramètre « {1} » avec System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute.Windows Runtime ne prend pas en charge le marquage de paramètres avec System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute. - - - Supprimez System.Runtime.InteropServices.InAttribute et remplacez System.Runtime.InteropServices.OutAttribute par le modificateur 'out' à la place. - - - Paramètre autre qu’un tableau marqué avec ReadOnlyArray ou WriteOnlyArray - - - La méthode '{0}' a un paramètre '{1}' qui n’est pas un tableau et qui possède un attribut ReadOnlyArray ou WriteOnlyArray. - - - Windows Runtime ne prend pas en charge le marquage de paramètres autres que tableau avec ReadOnlyArray ou WriteOnlyArray. - - - Interface non valide héritée - - - Le type de composant Windows Runtime {0} ne peut pas implémenter l’interface {1}, car l’interface n’est pas une interface Windows Runtime valide - - - Aucun type public défini - - - Les composants Windows Runtime doivent avoir au moins un type public - - - Surcharge d’opérateur exposée - - - {0} est une surcharge d’opérateur, les types managés ne peuvent pas exposer de surcharges d’opérateur dans le Windows Runtime - - - Règle de valeur nommée du paramètre - - - Le nom de paramètre {1} dans la méthode {0} est identique au nom du paramètre de valeur de retour utilisé dans l’interopérabilité C#/WinRT générée ; utiliser un autre nom de paramètre - - - La propriété doit avoir une méthode getter publique - - - La propriété '{0}' n’a pas de méthode getter publique. Windows Runtime ne prend pas en charge les propriétés setter uniquement. - {0} will be some user-defined keyword - - - Paramètre passé par référence - - - La méthode '{0}' a un paramètre '{1}' marqué 'ref'; les paramètres de référence ne sont pas autorisés dans Windows Runtime - - - Champ Const dans struct - - - Le {0} de structure a un champ const - les constantes ne peuvent apparaître que sur Windows Runtime énumérations. - - - Champ non valide dans struct - - - Le {0} de structure a un champ de type {1}; {1} n’est pas un type de champ Windows Runtime valide. - - - Chaque champ d’une structure Windows Runtime peut uniquement être UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum ou lui-même une structure. - - - Champ privé dans struct - - - Le {0} de structure a un champ non public. Tous les champs doivent être publics pour les structures Windows Runtime. - - - Règle de struct vide - - - La structure {0} ne contient aucun champ public. Windows Runtime structures doivent contenir au moins un champ public. - - - La classe implémente de manière incorrecte une interface - - - Le '{0}' de classe n’implémente pas correctement les '{1}' d’interface, car le '{2}' membre est manquant ou n’est pas public - - - La classe n’est pas scellée - - - L’exportation de types non scellés n’est pas prise en charge dans CsWinRT. Marquez le type {0} comme scellé - {0} will be some user-defined keyword - - - Exposition du type non prise en charge - - - Le membre '{0}' a le type '{1}' dans sa signature. - {0} and {1} will be user-defined keywords - - - Le type '{1}' n’est pas un type Windows Runtime valide. - {1} will be some user-defined keyword - - - Cependant, le type (ou ses paramètres génériques) implémente des interfaces qui sont des types Windows Runtime valides. - - - Changez le type « {1} » dans la signature de membre en l’un des types suivants à partir de System.Collections.Generic : {2}. - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Paramètre de tableau marqué InAttribute ou OutAttribute + + + La méthode '{0}' a un paramètre '{1}' qui est un tableau et qui a un System.Runtime.InteropServices.InAttribute ou system.Runtime.InteropServices.OutAttribute. + + + Dans le Windows Runtime, les paramètres de tableau doivent avoir ReadOnlyArray ou WriteOnlyArray. + + + Supprimez ces attributs ou remplacez-les par l’attribut Windows Runtime approprié si nécessaire. + + + Paramètre de tableau marqué `out` et ReadOnlyArray + + + La méthode '{0}' a un paramètre de sortie '{1}' qui est un tableau, mais qui a l’attribut ReadOnlyArray. + + + Dans le Windows Runtime, le contenu des tableaux de sortie est accessible en écriture. Supprimez l’attribut de '{1}'. + + + Paramètre de tableau marqué à la fois comme ReadOnlyArray et WriteOnlyArray + + + La méthode '{0}' a un paramètre '{1}' qui est un tableau et qui a ReadOnlyArray et WriteOnlyArray. + + + Dans le Windows Runtime, les paramètres du tableau de contenu doivent être lisibles ou accessibles en écriture. Supprimez l’un des attributs de '{1}'. + + + Paramètre de tableau non marqué avec ReadOnlyArray ou WriteOnlyArray + + + La méthode '{0}' a un paramètre '{1}' qui est un tableau. + + + Dans le Windows Runtime, le contenu des paramètres de tableau doit être lisible ou accessible en écriture ; appliquez ReadOnlyArray ou WriteOnlyArray à '{1}'. + + + Règle de constructeur de classe + + + Les classes ne peuvent pas avoir plusieurs constructeurs de la même arité dans le Windows Runtime, la classe {0} a plusieurs constructeurs d’arité {1} + + + L’espace de noms est disjoint de l’espace de noms principal (winmd) + + + Un type public a un espace de noms ('{1}') qui ne partage aucun préfixe commun avec d’autres espaces de noms ('{0}'). + {1} and {0} will be some user-defined keyword + + + Tous les types d’un fichier de métadonnées Windows doivent exister dans un sous-espace de noms de l’espace de noms qui est impliqué par le nom de fichier. + "sub namespace" means a namespace defined within another namespace + + + La classe (ou l’interface) est générique + + + Le type {0} est générique, les types Windows Runtime ne peuvent pas être génériques + {0} will be some user-defined keyword + + + Signature de tableau trouvée avec un tableau en escalier, qui n’est pas un type WinRT valide + + + La méthode {0} a un tableau imbriqué de type {1} dans sa signature ; les tableaux dans Windows Runtime signature de méthode ne peuvent pas être imbriqués + + + Signature de tableau trouvée avec un tableau multidimensionnel, qui n’est pas un type Windows Runtime valide + + + La méthode « {0} » possède un tableau multidimensionnel de type « {1} » dans sa signature ; les tableaux dans les signatures de méthode Windows Runtime doivent être unidimensionnels + + + Une seule surcharge doit être désignée par défaut + + + Dans la classe {2} : plusieurs surcharges de {0}-paramètre de « {1} » sont décorées avec Windows.Foundation.Metadata.DefaultOverloadAttribute. + + + L’attribut ne peut être appliqué qu’à une seule surcharge de la méthode. + + + Les noms d’espaces de noms ne peuvent pas différer uniquement par la casse + + + Plusieurs espaces de noms portant le nom '{0}'; les noms d’espace de noms ne peuvent pas différer uniquement par la casse dans le Windows Runtime + {0} will be some user-defined keyword + + + Surcharges multiples rencontrées sans attribut DefaultOverload + + + Dans la classe {2} : les surcharges de {0}-paramètre de {1} doivent avoir exactement une méthode spécifiée comme surcharge par défaut en la décorant avec Windows.Foundation.Metadata.DefaultOverloadAttribute + + + Paramètre (non de type de tableau) marqué InAttribute ou OutAttribute + + + La méthode « {0} » a un paramètre « {1} » avec System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute.Windows Runtime ne prend pas en charge le marquage de paramètres avec System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute. + + + Supprimez System.Runtime.InteropServices.InAttribute et remplacez System.Runtime.InteropServices.OutAttribute par le modificateur 'out' à la place. + + + Paramètre autre qu’un tableau marqué avec ReadOnlyArray ou WriteOnlyArray + + + La méthode '{0}' a un paramètre '{1}' qui n’est pas un tableau et qui possède un attribut ReadOnlyArray ou WriteOnlyArray. + + + Windows Runtime ne prend pas en charge le marquage de paramètres autres que tableau avec ReadOnlyArray ou WriteOnlyArray. + + + Interface non valide héritée + + + Le type de composant Windows Runtime {0} ne peut pas implémenter l’interface {1}, car l’interface n’est pas une interface Windows Runtime valide + + + Aucun type public défini + + + Les composants Windows Runtime doivent avoir au moins un type public + + + Surcharge d’opérateur exposée + + + {0} est une surcharge d’opérateur, les types managés ne peuvent pas exposer de surcharges d’opérateur dans le Windows Runtime + + + Règle de valeur nommée du paramètre + + + Le nom de paramètre {1} dans la méthode {0} est identique au nom du paramètre de valeur de retour utilisé dans l’interopérabilité C#/WinRT générée ; utiliser un autre nom de paramètre + + + La propriété doit avoir une méthode getter publique + + + La propriété '{0}' n’a pas de méthode getter publique. Windows Runtime ne prend pas en charge les propriétés setter uniquement. + {0} will be some user-defined keyword + + + Paramètre passé par référence + + + La méthode '{0}' a un paramètre '{1}' marqué 'ref'; les paramètres de référence ne sont pas autorisés dans Windows Runtime + + + Champ Const dans struct + + + Le {0} de structure a un champ const - les constantes ne peuvent apparaître que sur Windows Runtime énumérations. + + + Champ non valide dans struct + + + Le {0} de structure a un champ de type {1}; {1} n’est pas un type de champ Windows Runtime valide. + + + Chaque champ d’une structure Windows Runtime peut uniquement être UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum ou lui-même une structure. + + + Champ privé dans struct + + + Le {0} de structure a un champ non public. Tous les champs doivent être publics pour les structures Windows Runtime. + + + Règle de struct vide + + + La structure {0} ne contient aucun champ public. Windows Runtime structures doivent contenir au moins un champ public. + + + La classe implémente de manière incorrecte une interface + + + Le '{0}' de classe n’implémente pas correctement les '{1}' d’interface, car le '{2}' membre est manquant ou n’est pas public + + + La classe n’est pas scellée + + + L’exportation de types non scellés n’est pas prise en charge dans CsWinRT. Marquez le type {0} comme scellé + {0} will be some user-defined keyword + + + Exposition du type non prise en charge + + + Le membre '{0}' a le type '{1}' dans sa signature. + {0} and {1} will be user-defined keywords + + + Le type '{1}' n’est pas un type Windows Runtime valide. + {1} will be some user-defined keyword + + + Cependant, le type (ou ses paramètres génériques) implémente des interfaces qui sont des types Windows Runtime valides. + + + Changez le type « {1} » dans la signature de membre en l’un des types suivants à partir de System.Collections.Generic : {2}. + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/it-IT/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/it-IT/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/it-IT/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/it-IT/CsWinRTDiagnosticStrings.resx index 4cf988ab9..84e2e9140 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/it-IT/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/it-IT/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Parametro di matrice contrassegnato come InAttribute o OutAttribute - - - Il metodo '{0}' ha un parametro '{1}' che è una matrice e che contiene System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute. - - - Nel Windows Runtime i parametri di matrice devono avere ReadOnlyArray o WriteOnlyArray. - - - Rimuovere questi attributi o sostituirli con l'attributo Windows Runtime appropriato, se necessario. - - - Parametro di matrice contrassegnato come 'out' e ReadOnlyArray - - - Il metodo '{0}' dispone di un parametro di output '{1}' che è una matrice, ma che ha l'attributo ReadOnlyArray. - - - Nel Windows Runtime, il contenuto delle matrici di output è scrivibile. Rimuovere l'attributo dal '{1}'. - - - Parametro di matrice contrassegnato sia come ReadOnlyArray che come WriteOnlyArray - - - Il metodo '{0}' ha un parametro '{1}' che è una matrice e che contiene sia ReadOnlyArray che WriteOnlyArray. - - - Nel Windows Runtime i parametri della matrice del contenuto devono essere leggibili o scrivibili. Rimuovere uno degli attributi dal '{1}'. - - - Parametro di matrice non contrassegnato come ReadOnlyArray o WriteOnlyArray - - - Il metodo '{0}' contiene un '{1}' di parametro che è una matrice. - - - Nel Windows Runtime, il contenuto dei parametri della matrice deve essere leggibile o scrivibile; applicare ReadOnlyArray o WriteOnlyArray a '{1}'. - - - Regola costruttore classe - - - Le classi non possono avere più costruttori dello stesso grado nel Windows Runtime. La classe {0} ha più costruttori {1}-arity - - - Lo spazio dei nomi è disgiunto dallo spazio dei nomi principale (winmd) - - - Uno spazio dei nomi ('{1}') di un tipo pubblico non condivide alcun prefisso comune con altri spazi dei nomi ('{0}'). - {1} and {0} will be some user-defined keyword - - - Tutti i tipi all'interno di un file di metadati Windows devono essere presenti in uno spazio dei nomi secondario dello spazio dei nomi implicito nel nome del file. - "sub namespace" means a namespace defined within another namespace - - - La classe (o l'interfaccia) è generica - - - Il tipo {0} è generico, Windows Runtime tipi non possono essere generici - {0} will be some user-defined keyword - - - È stata trovata una firma della matrice con matrice di matrici, che non è un tipo WinRT valido - - - Nella firma del metodo {0} è presente una matrice annidata di tipo {1}; non è possibile annidare matrici nella firma del metodo Windows Runtime - - - Trovata firma di matrice con matrice multidimensionale, che non è un tipo di Windows Runtime valido - - - Nella firma del metodo '{0}' è presente una matrice multidimensionale di tipo '{1}'. le matrici nelle firme del metodo Windows Runtime devono essere unidimensionali - - - È necessario designare come predefinito un solo overload - - - Nella classe {2}: più overload di parametri {0} di '{1}' sono decorati con Windows.Foundation.Metadata.DefaultOverloadAttribute. - - - L'attributo può essere applicato solo a un overload del metodo. - - - I nomi degli spazi dei nomi non possono differire solo per maiuscole e minuscole - - - Sono stati trovati più spazi dei nomi con il nome '{0}'; i nomi degli spazi dei nomi non possono differire solo per la distinzione tra maiuscole e minuscole nel Windows Runtime - {0} will be some user-defined keyword - - - Più overload rilevati senza attributo DefaultOverload - - - Nella classe {2}: per gli overload del parametro {0} di {1} deve essere specificato esattamente un metodo come overload predefinito decorandolo con Windows.Foundation.Metadata.DefaultOverloadAttribute - - - Parametro (non tipo matrice) contrassegnato come InAttribute o OutAttribute - - - Il metodo '{0}' ha un parametro '{1}' con System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute.Windows Runtime non supporta il contrassegno di parametri con System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute. - - - Provare a rimuovere System.Runtime.InteropServices.InAttribute e sostituire System.Runtime.InteropServices.OutAttribute con il modificatore 'out'. - - - Parametro non di matrice contrassegnato con ReadOnlyArray o WriteOnlyArray - - - Il metodo '{0}' ha un parametro '{1}' che non è una matrice e che ha un attributo ReadOnlyArray o WriteOnlyArray. - - - Windows Runtime non supporta il contrassegno di parametri non di matrice con ReadOnlyArray o WriteOnlyArray. - - - Interfaccia ereditata non valida - - - Windows Runtime tipo di componente {0} non può implementare l'interfaccia {1}. L'interfaccia non è un'interfaccia Windows Runtime valida - - - Nessun tipo pubblico definito - - - I componenti Windows Runtime devono avere almeno un tipo pubblico - - - Overload dell'operatore esposto - - - {0} è un overload dell'operatore. I tipi gestiti non possono esporre overload di operatori nel Windows Runtime - - - Regola del valore denominato del parametro - - - Il nome del parametro {1} nel metodo {0} è uguale al nome del parametro del valore restituito utilizzato nell'interoperabilità C#/WinRT generata; usa un nome di parametro diverso - - - La proprietà deve avere un getter pubblico - - - La proprietà '{0}' non dispone di un metodo getter pubblico. Windows Runtime non supporta proprietà solo setter. - {0} will be some user-defined keyword - - - Parametro passato per riferimento - - - Il metodo '{0}' ha un parametro '{1}' contrassegnato come 'ref'; parametri di riferimento non consentiti in Windows Runtime - - - Campo costante nello struct - - - La struttura {0} contiene un campo costante. Le costanti possono essere visualizzate solo nelle enumerazioni Windows Runtime. - - - Campo non valido nello struct - - - La struttura {0} ha un campo di tipo {1}; {1} non è un tipo di campo Windows Runtime valido. - - - Ogni campo di una struttura Windows Runtime può essere solo UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum o una struttura stessa. - - - Campo privato nello struct - - - La struttura {0} contiene un campo non pubblico. Tutti i campi devono essere pubblici per le strutture Windows Runtime. - - - Regola di struct vuota - - - La struttura {0} non contiene campi pubblici. Windows Runtime strutture devono contenere almeno un campo pubblico. - - - La classe implementa in modo errato un'interfaccia - - - La classe '{0}' non implementa correttamente l'interfaccia '{1}' perché il '{2}' membro è mancante o non pubblico - - - Classe non eseguito - - - L'esportazione di tipi non sealed non è supportata in CsWinRT. Contrassegnare il tipo {0} come sealed - {0} will be some user-defined keyword - - - Esposizione del tipo non supportato - - - Il '{0}' membro ha il tipo '{1}' nella relativa firma. - {0} and {1} will be user-defined keywords - - - Il tipo '{1}' non è un tipo di Windows Runtime valido. - {1} will be some user-defined keyword - - - Tuttavia, il tipo (o i relativi parametri generici) implementa interfacce valide Windows Runtime tipi. - - - Provare a modificare il tipo '{1} nella firma del membro in uno dei tipi seguenti da System.Collections.Generic: {2}. - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Parametro di matrice contrassegnato come InAttribute o OutAttribute + + + Il metodo '{0}' ha un parametro '{1}' che è una matrice e che contiene System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute. + + + Nel Windows Runtime i parametri di matrice devono avere ReadOnlyArray o WriteOnlyArray. + + + Rimuovere questi attributi o sostituirli con l'attributo Windows Runtime appropriato, se necessario. + + + Parametro di matrice contrassegnato come 'out' e ReadOnlyArray + + + Il metodo '{0}' dispone di un parametro di output '{1}' che è una matrice, ma che ha l'attributo ReadOnlyArray. + + + Nel Windows Runtime, il contenuto delle matrici di output è scrivibile. Rimuovere l'attributo dal '{1}'. + + + Parametro di matrice contrassegnato sia come ReadOnlyArray che come WriteOnlyArray + + + Il metodo '{0}' ha un parametro '{1}' che è una matrice e che contiene sia ReadOnlyArray che WriteOnlyArray. + + + Nel Windows Runtime i parametri della matrice del contenuto devono essere leggibili o scrivibili. Rimuovere uno degli attributi dal '{1}'. + + + Parametro di matrice non contrassegnato come ReadOnlyArray o WriteOnlyArray + + + Il metodo '{0}' contiene un '{1}' di parametro che è una matrice. + + + Nel Windows Runtime, il contenuto dei parametri della matrice deve essere leggibile o scrivibile; applicare ReadOnlyArray o WriteOnlyArray a '{1}'. + + + Regola costruttore classe + + + Le classi non possono avere più costruttori dello stesso grado nel Windows Runtime. La classe {0} ha più costruttori {1}-arity + + + Lo spazio dei nomi è disgiunto dallo spazio dei nomi principale (winmd) + + + Uno spazio dei nomi ('{1}') di un tipo pubblico non condivide alcun prefisso comune con altri spazi dei nomi ('{0}'). + {1} and {0} will be some user-defined keyword + + + Tutti i tipi all'interno di un file di metadati Windows devono essere presenti in uno spazio dei nomi secondario dello spazio dei nomi implicito nel nome del file. + "sub namespace" means a namespace defined within another namespace + + + La classe (o l'interfaccia) è generica + + + Il tipo {0} è generico, Windows Runtime tipi non possono essere generici + {0} will be some user-defined keyword + + + È stata trovata una firma della matrice con matrice di matrici, che non è un tipo WinRT valido + + + Nella firma del metodo {0} è presente una matrice annidata di tipo {1}; non è possibile annidare matrici nella firma del metodo Windows Runtime + + + Trovata firma di matrice con matrice multidimensionale, che non è un tipo di Windows Runtime valido + + + Nella firma del metodo '{0}' è presente una matrice multidimensionale di tipo '{1}'. le matrici nelle firme del metodo Windows Runtime devono essere unidimensionali + + + È necessario designare come predefinito un solo overload + + + Nella classe {2}: più overload di parametri {0} di '{1}' sono decorati con Windows.Foundation.Metadata.DefaultOverloadAttribute. + + + L'attributo può essere applicato solo a un overload del metodo. + + + I nomi degli spazi dei nomi non possono differire solo per maiuscole e minuscole + + + Sono stati trovati più spazi dei nomi con il nome '{0}'; i nomi degli spazi dei nomi non possono differire solo per la distinzione tra maiuscole e minuscole nel Windows Runtime + {0} will be some user-defined keyword + + + Più overload rilevati senza attributo DefaultOverload + + + Nella classe {2}: per gli overload del parametro {0} di {1} deve essere specificato esattamente un metodo come overload predefinito decorandolo con Windows.Foundation.Metadata.DefaultOverloadAttribute + + + Parametro (non tipo matrice) contrassegnato come InAttribute o OutAttribute + + + Il metodo '{0}' ha un parametro '{1}' con System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute.Windows Runtime non supporta il contrassegno di parametri con System.Runtime.InteropServices.InAttribute o System.Runtime.InteropServices.OutAttribute. + + + Provare a rimuovere System.Runtime.InteropServices.InAttribute e sostituire System.Runtime.InteropServices.OutAttribute con il modificatore 'out'. + + + Parametro non di matrice contrassegnato con ReadOnlyArray o WriteOnlyArray + + + Il metodo '{0}' ha un parametro '{1}' che non è una matrice e che ha un attributo ReadOnlyArray o WriteOnlyArray. + + + Windows Runtime non supporta il contrassegno di parametri non di matrice con ReadOnlyArray o WriteOnlyArray. + + + Interfaccia ereditata non valida + + + Windows Runtime tipo di componente {0} non può implementare l'interfaccia {1}. L'interfaccia non è un'interfaccia Windows Runtime valida + + + Nessun tipo pubblico definito + + + I componenti Windows Runtime devono avere almeno un tipo pubblico + + + Overload dell'operatore esposto + + + {0} è un overload dell'operatore. I tipi gestiti non possono esporre overload di operatori nel Windows Runtime + + + Regola del valore denominato del parametro + + + Il nome del parametro {1} nel metodo {0} è uguale al nome del parametro del valore restituito utilizzato nell'interoperabilità C#/WinRT generata; usa un nome di parametro diverso + + + La proprietà deve avere un getter pubblico + + + La proprietà '{0}' non dispone di un metodo getter pubblico. Windows Runtime non supporta proprietà solo setter. + {0} will be some user-defined keyword + + + Parametro passato per riferimento + + + Il metodo '{0}' ha un parametro '{1}' contrassegnato come 'ref'; parametri di riferimento non consentiti in Windows Runtime + + + Campo costante nello struct + + + La struttura {0} contiene un campo costante. Le costanti possono essere visualizzate solo nelle enumerazioni Windows Runtime. + + + Campo non valido nello struct + + + La struttura {0} ha un campo di tipo {1}; {1} non è un tipo di campo Windows Runtime valido. + + + Ogni campo di una struttura Windows Runtime può essere solo UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum o una struttura stessa. + + + Campo privato nello struct + + + La struttura {0} contiene un campo non pubblico. Tutti i campi devono essere pubblici per le strutture Windows Runtime. + + + Regola di struct vuota + + + La struttura {0} non contiene campi pubblici. Windows Runtime strutture devono contenere almeno un campo pubblico. + + + La classe implementa in modo errato un'interfaccia + + + La classe '{0}' non implementa correttamente l'interfaccia '{1}' perché il '{2}' membro è mancante o non pubblico + + + Classe non eseguito + + + L'esportazione di tipi non sealed non è supportata in CsWinRT. Contrassegnare il tipo {0} come sealed + {0} will be some user-defined keyword + + + Esposizione del tipo non supportato + + + Il '{0}' membro ha il tipo '{1}' nella relativa firma. + {0} and {1} will be user-defined keywords + + + Il tipo '{1}' non è un tipo di Windows Runtime valido. + {1} will be some user-defined keyword + + + Tuttavia, il tipo (o i relativi parametri generici) implementa interfacce valide Windows Runtime tipi. + + + Provare a modificare il tipo '{1} nella firma del membro in uno dei tipi seguenti da System.Collections.Generic: {2}. + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/ja-JP/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ja-JP/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/ja-JP/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ja-JP/CsWinRTDiagnosticStrings.resx index 94cdc1a1f..84489f511 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/ja-JP/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ja-JP/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 配列パラメーターが InAttribute または OutAttribute に設定されています - - - メソッド '{0}'には、配列であるパラメーター '{1}'があり、System.Runtime.InteropServices.InAttribute または System.Runtime.InteropServices.OutAttribute を持っています。 - - - Windows ランタイムでは、配列パラメーターには ReadOnlyArray または WriteOnlyArray が必要です。 - - - これらの属性を削除するか、必要に応じて適切な Windows ランタイム属性に置き換えてください。 - - - 配列パラメーターが 'out' および ReadOnlyArray に設定されています - - - メソッド '{0}' には、配列である出力パラメーター '{1}' がありますが、ReadOnlyArray 属性を持っています。 - - - Windows ランタイムでは、出力配列の内容は書き込み可能です。属性を'{1}'から削除してください。 - - - ReadOnlyArray と WriteOnlyArray の両方をマークした配列パラメーター - - - メソッド '{0}' には、配列であり、ReadOnlyArray と WriteOnlyArray の両方を持つパラメーター '{1}' があります。 - - - Windows ランタイムでは、コンテンツ配列パラメーターは読み取り可能または書き込み可能である必要があります。属性の 1 つを '{1}' から削除してください。 - - - ReadOnlyArray または WriteOnlyArray の方法でマークされていない配列パラメーター - - - メソッド '{0}'に、配列であるパラメーター '{1}'があります。 - - - Windows ランタイムでは、配列パラメーターの内容を読み取り可能または書き込み可能にする必要があります。ReadOnlyArray または WriteOnlyArray を'{1}'に適用してください。 - - - クラス コンストラクター ルール - - - クラスは、Windows ランタイムで同じアリティの複数のコンストラクターを持つことはできません。クラス {0} には、複数の {1} アリティ コンストラクターがあります。 - - - 名前空間がメイン (winmd) 名前空間から離れています - - - パブリック型に、共通のプレフィックスを他の名前空間 ('{0}') と共有しない名前空間 ('{1}') があります。 - {1} and {0} will be some user-defined keyword - - - Windows メタデータ ファイル内のすべての型は、ファイル名によって示される名前空間のサブ名前空間に存在する必要があります。 - "sub namespace" means a namespace defined within another namespace - - - クラス (またはインターフェイス) はジェネリックです - - - 型 {0} はジェネリックであり、Windows ランタイムの種類はジェネリックにすることはできません - {0} will be some user-defined keyword - - - ジャグ配列で配列シグネチャが見つかりましたが、これは有効な WinRT 型ではありません - - - メソッド {0} のシグネチャには、型 {1} のネストされた配列があります。Windows ランタイム メソッド シグネチャの配列はネストできません - - - 有効な Windows ランタイムの種類ではない多次元配列で見つかった配列シグネチャ - - - メソッド '{0}' のシグネチャには、型 '{1}' の多次元配列があります。Windows ランタイム メソッド シグネチャの配列は 1 次元である必要があります - - - 1 つのオーバーロードのみを既定として指定する必要があります - - - クラス {2} の場合: '{1}' の複数の {0} パラメーターのオーバーロードは、Windows.Foundation.Metadata.DefaultOverloadAttribute で装飾されます。 - - - 属性は、メソッドの 1 つのオーバーロードにのみ適用できます。 - - - 名前空間名は大文字と小文字だけで異なることはできません - - - '{0}' という名前で複数の名前空間が見つかりました; 名前空間名は、Windows ランタイムでは大文字と小文字だけで異なることはできません - {0} will be some user-defined keyword - - - DefaultOverload 属性なしで見られる複数のオーバーロード - - - クラス {2} の場合: {1} の {0} パラメーターのオーバーロードには、Windows.Foundation.Metadata.DefaultOverloadAttribute で装飾することにより、既定のオーバーロードとして 1 つのメソッドを指定する必要があります。 - - - InAttribute または OutAttribute に設定されたパラメーター (配列型ではありません) - - - メソッド '{0}' には、System.Runtime.InteropServices.InAttribute または System.Runtime.InteropServices.OutAttribute.Windows ランタイムを使用したパラメーター '{1}' があり、System.Runtime.InteropServices.InAttribute または System.Runtime.InteropServices.OutAttribute を使用したパラメーターのマーキングはサポートされていません。 - - - System.Runtime.InteropServices.InAttribute を削除することを検討し、代わりに System.Runtime.InteropServices.OutAttribute を 'out' 修飾子に置き換えてください。 - - - ReadOnlyArray または WriteOnlyArray でマークされた非配列パラメーター - - - メソッド '{0}' に、配列ではなく、ReadOnlyArray 属性または WriteOnlyArray 属性を持つパラメーター '{1}'があります。 - - - Windows ランタイムは、ReadOnlyArray または WriteOnlyArray による非配列パラメーターのマーキングをサポートしていません。 - - - 無効なインターフェイスが継承されました - - - インターフェイスが有効な Windows ランタイム インターフェイスではないため、Windows ランタイム コンポーネントの型 {0} はインターフェイス {1} を実装できません - - - パブリック型は定義されていません - - - Windows ランタイム コンポーネントには少なくとも 1 つのパブリック型が必要です - - - 演算子のオーバーロードが公開されました - - - {0} は演算子のオーバーロードであり、マネージ型は Windows ランタイムで演算子のオーバーロードを公開できません - - - パラメータ名前付き値ルール - - - メソッド {0} のパラメーター名{1}が、生成された C#/WinRT 相互運用機能で使用される戻り値パラメーター名と同じです。別のパラメーター名を使用する - - - プロパティにはパブリック ゲッターが必要です - - - プロパティ '{0}' にパブリック ゲッター メソッドがありません。Windows ランタイムはセッター専用プロパティをサポートしていません。 - {0} will be some user-defined keyword - - - 参照によって渡されたパラメーター - - - メソッド '{0}' には、'ref' とマークされたパラメーター '{1}' があります。参照パラメーターは Windows ランタイムでは許可されていません - - - 構造体の Const フィールド - - - 構造体 {0} には const フィールドがあります - 定数は Windows ランタイム列挙にのみ表示できます。 - - - 構造体の無効なフィールド - - - 構造体{0}に型 {1}; のフィールドがあります。{1}は有効なWindows ランタイムフィールドの種類ではありません。 - - - Windows ランタイム構造体の各フィールドには、UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、Single、Double、Boolean、String、Enum、またはその構造体のみを指定できます。 - - - 構造体内のプライベート フィールド - - - 構造体 {0} には非公開フィールドがあります。Windows ランタイム構造体では、すべてのフィールドがパブリックである必要があります。 - - - 空の構造体ルール - - - 構造体 {0} にはパブリック フィールドは含まれていません。Windows ランタイム構造体には、少なくとも 1 つのパブリック フィールドが含まれている必要があります。 - - - クラスがインターフェイスを誤って実装しています - - - メンバー '{2}' が見つからないかパブリックでないため、クラス '{0}' はインターフェイス '{1}' を正しく実装しません - - - クラスが封印されていません - - - 封印されていない型のエクスポートは CsWinRT ではサポートされていません。型 {0} を封印済みとしてマークしてください - {0} will be some user-defined keyword - - - サポートされていない型を公開しています - - - メンバー '{0}'のシグネチャに'{1}'型が含まれています。 - {0} and {1} will be user-defined keywords - - - 型'{1}'は有効なWindows ランタイム型ではありません。 - {1} will be some user-defined keyword - - - ただし、型 (またはそのジェネリック パラメーター) は、有効な Windows ランタイムの種類であるインターフェイスを実装します。 - - - メンバー シグネチャの型 '{1} を System.Collections.Generic から次の種類のいずれかに変更することを検討してください: {2}。 - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 配列パラメーターが InAttribute または OutAttribute に設定されています + + + メソッド '{0}'には、配列であるパラメーター '{1}'があり、System.Runtime.InteropServices.InAttribute または System.Runtime.InteropServices.OutAttribute を持っています。 + + + Windows ランタイムでは、配列パラメーターには ReadOnlyArray または WriteOnlyArray が必要です。 + + + これらの属性を削除するか、必要に応じて適切な Windows ランタイム属性に置き換えてください。 + + + 配列パラメーターが 'out' および ReadOnlyArray に設定されています + + + メソッド '{0}' には、配列である出力パラメーター '{1}' がありますが、ReadOnlyArray 属性を持っています。 + + + Windows ランタイムでは、出力配列の内容は書き込み可能です。属性を'{1}'から削除してください。 + + + ReadOnlyArray と WriteOnlyArray の両方をマークした配列パラメーター + + + メソッド '{0}' には、配列であり、ReadOnlyArray と WriteOnlyArray の両方を持つパラメーター '{1}' があります。 + + + Windows ランタイムでは、コンテンツ配列パラメーターは読み取り可能または書き込み可能である必要があります。属性の 1 つを '{1}' から削除してください。 + + + ReadOnlyArray または WriteOnlyArray の方法でマークされていない配列パラメーター + + + メソッド '{0}'に、配列であるパラメーター '{1}'があります。 + + + Windows ランタイムでは、配列パラメーターの内容を読み取り可能または書き込み可能にする必要があります。ReadOnlyArray または WriteOnlyArray を'{1}'に適用してください。 + + + クラス コンストラクター ルール + + + クラスは、Windows ランタイムで同じアリティの複数のコンストラクターを持つことはできません。クラス {0} には、複数の {1} アリティ コンストラクターがあります。 + + + 名前空間がメイン (winmd) 名前空間から離れています + + + パブリック型に、共通のプレフィックスを他の名前空間 ('{0}') と共有しない名前空間 ('{1}') があります。 + {1} and {0} will be some user-defined keyword + + + Windows メタデータ ファイル内のすべての型は、ファイル名によって示される名前空間のサブ名前空間に存在する必要があります。 + "sub namespace" means a namespace defined within another namespace + + + クラス (またはインターフェイス) はジェネリックです + + + 型 {0} はジェネリックであり、Windows ランタイムの種類はジェネリックにすることはできません + {0} will be some user-defined keyword + + + ジャグ配列で配列シグネチャが見つかりましたが、これは有効な WinRT 型ではありません + + + メソッド {0} のシグネチャには、型 {1} のネストされた配列があります。Windows ランタイム メソッド シグネチャの配列はネストできません + + + 有効な Windows ランタイムの種類ではない多次元配列で見つかった配列シグネチャ + + + メソッド '{0}' のシグネチャには、型 '{1}' の多次元配列があります。Windows ランタイム メソッド シグネチャの配列は 1 次元である必要があります + + + 1 つのオーバーロードのみを既定として指定する必要があります + + + クラス {2} の場合: '{1}' の複数の {0} パラメーターのオーバーロードは、Windows.Foundation.Metadata.DefaultOverloadAttribute で装飾されます。 + + + 属性は、メソッドの 1 つのオーバーロードにのみ適用できます。 + + + 名前空間名は大文字と小文字だけで異なることはできません + + + '{0}' という名前で複数の名前空間が見つかりました; 名前空間名は、Windows ランタイムでは大文字と小文字だけで異なることはできません + {0} will be some user-defined keyword + + + DefaultOverload 属性なしで見られる複数のオーバーロード + + + クラス {2} の場合: {1} の {0} パラメーターのオーバーロードには、Windows.Foundation.Metadata.DefaultOverloadAttribute で装飾することにより、既定のオーバーロードとして 1 つのメソッドを指定する必要があります。 + + + InAttribute または OutAttribute に設定されたパラメーター (配列型ではありません) + + + メソッド '{0}' には、System.Runtime.InteropServices.InAttribute または System.Runtime.InteropServices.OutAttribute.Windows ランタイムを使用したパラメーター '{1}' があり、System.Runtime.InteropServices.InAttribute または System.Runtime.InteropServices.OutAttribute を使用したパラメーターのマーキングはサポートされていません。 + + + System.Runtime.InteropServices.InAttribute を削除することを検討し、代わりに System.Runtime.InteropServices.OutAttribute を 'out' 修飾子に置き換えてください。 + + + ReadOnlyArray または WriteOnlyArray でマークされた非配列パラメーター + + + メソッド '{0}' に、配列ではなく、ReadOnlyArray 属性または WriteOnlyArray 属性を持つパラメーター '{1}'があります。 + + + Windows ランタイムは、ReadOnlyArray または WriteOnlyArray による非配列パラメーターのマーキングをサポートしていません。 + + + 無効なインターフェイスが継承されました + + + インターフェイスが有効な Windows ランタイム インターフェイスではないため、Windows ランタイム コンポーネントの型 {0} はインターフェイス {1} を実装できません + + + パブリック型は定義されていません + + + Windows ランタイム コンポーネントには少なくとも 1 つのパブリック型が必要です + + + 演算子のオーバーロードが公開されました + + + {0} は演算子のオーバーロードであり、マネージ型は Windows ランタイムで演算子のオーバーロードを公開できません + + + パラメータ名前付き値ルール + + + メソッド {0} のパラメーター名{1}が、生成された C#/WinRT 相互運用機能で使用される戻り値パラメーター名と同じです。別のパラメーター名を使用する + + + プロパティにはパブリック ゲッターが必要です + + + プロパティ '{0}' にパブリック ゲッター メソッドがありません。Windows ランタイムはセッター専用プロパティをサポートしていません。 + {0} will be some user-defined keyword + + + 参照によって渡されたパラメーター + + + メソッド '{0}' には、'ref' とマークされたパラメーター '{1}' があります。参照パラメーターは Windows ランタイムでは許可されていません + + + 構造体の Const フィールド + + + 構造体 {0} には const フィールドがあります - 定数は Windows ランタイム列挙にのみ表示できます。 + + + 構造体の無効なフィールド + + + 構造体{0}に型 {1}; のフィールドがあります。{1}は有効なWindows ランタイムフィールドの種類ではありません。 + + + Windows ランタイム構造体の各フィールドには、UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、Single、Double、Boolean、String、Enum、またはその構造体のみを指定できます。 + + + 構造体内のプライベート フィールド + + + 構造体 {0} には非公開フィールドがあります。Windows ランタイム構造体では、すべてのフィールドがパブリックである必要があります。 + + + 空の構造体ルール + + + 構造体 {0} にはパブリック フィールドは含まれていません。Windows ランタイム構造体には、少なくとも 1 つのパブリック フィールドが含まれている必要があります。 + + + クラスがインターフェイスを誤って実装しています + + + メンバー '{2}' が見つからないかパブリックでないため、クラス '{0}' はインターフェイス '{1}' を正しく実装しません + + + クラスが封印されていません + + + 封印されていない型のエクスポートは CsWinRT ではサポートされていません。型 {0} を封印済みとしてマークしてください + {0} will be some user-defined keyword + + + サポートされていない型を公開しています + + + メンバー '{0}'のシグネチャに'{1}'型が含まれています。 + {0} and {1} will be user-defined keywords + + + 型'{1}'は有効なWindows ランタイム型ではありません。 + {1} will be some user-defined keyword + + + ただし、型 (またはそのジェネリック パラメーター) は、有効な Windows ランタイムの種類であるインターフェイスを実装します。 + + + メンバー シグネチャの型 '{1} を System.Collections.Generic から次の種類のいずれかに変更することを検討してください: {2}。 + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/ko-KR/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ko-KR/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/ko-KR/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ko-KR/CsWinRTDiagnosticStrings.resx index d1e7141ca..ac71b9015 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/ko-KR/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ko-KR/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - InAttribute 또는 OutAttribute로 표시된 배열 매개 변수 - - - '{0}' 메서드에 배열인 매개 변수 '{1}' System.Runtime.InteropServices.InAttribute 또는 System.Runtime.InteropServices.OutAttribute가 있는 매개 변수가 있습니다. - - - Windows 런타임에서 배열 매개 변수에는 ReadOnlyArray 또는 WriteOnlyArray가 있어야 합니다. - - - 이러한 특성을 제거하거나 필요한 경우 적절한 Windows 런타임 특성으로 바꾸십시오. - - - 'out'으로 표시된 배열 매개 변수 및 ReadOnlyArray - - - 메서드 '{0}' 배열이지만 ReadOnlyArray 특성이 있는 출력 매개 변수 '{1}' 있습니다. - - - Windows 런타임 출력 배열의 내용을 쓸 수 있습니다. '{1}' 특성을 제거하십시오. - - - ReadOnlyArray 및 WriteOnlyArray 모두로 표시된 배열 매개 변수 - - - '{0}' 메서드에 배열인 매개 변수 '{1}' ReadOnlyArray와 WriteOnlyArray가 둘 다 있습니다. - - - Windows 런타임에서 콘텐츠 배열 매개 변수는 읽기 또는 쓰기가 가능해야 합니다. '{1}'에서 특성 중 하나를 제거하세요. - - - 배열 매개 변수가 ReadOnlyArray 또는 WriteOnlyArray 방식으로 표시되지 않았습니다. - - - '{0}' 메서드에 배열인 매개 변수 '{1}' 있습니다. - - - Windows 런타임 배열 매개 변수의 내용은 읽기 가능하거나 쓰기 가능해야 합니다. readOnlyArray 또는 WriteOnlyArray를 '{1}' 적용하세요. - - - 클래스 생성자 규칙 - - - 클래스는 Windows 런타임에서 동일한 arity의 여러 생성자를 가질 수 없습니다. 클래스 {0}에는 여러 {1}-arity 생성자가 있습니다. - - - 네임스페이스가 기본(winmd) 네임스페이스와 분리되어 있습니다. - - - public 형식에 다른 네임스페이스와 공통 접두사를 공유하지 않는 네임스페이스('{1}')가 있습니다('{0}'). - {1} and {0} will be some user-defined keyword - - - Windows 메타데이터 파일 내의 모든 형식은 파일 이름에 포함된 네임스페이스의 하위 네임스페이스에 있어야 합니다. - "sub namespace" means a namespace defined within another namespace - - - 클래스(또는 인터페이스)가 일반적입니다. - - - 형식 {0} 제네릭이므로 Windows 런타임 형식은 제네릭일 수 없습니다. - {0} will be some user-defined keyword - - - 유효한 WinRT 유형이 아닌 들쭉날쭉한 배열로 배열 서명을 찾았습니다. - - - 메서드 {0} 시그니처에 {1} 형식의 중첩 배열이 있습니다. Windows 런타임 메서드 시그니처의 배열은 중첩될 수 없습니다. - - - 유효한 Windows 런타임 유형이 아닌 다차원 배열로 배열 서명을 찾았습니다. - - - 메서드 '{0}' 시그니처에 '{1}' 형식의 다차원 배열이 있습니다. Windows 런타임 메서드 시그니처의 배열은 1차원이어야 합니다. - - - 하나의 과부하만 기본값으로 지정해야 합니다. - - - 클래스 {2}에서: '{1}'의 여러 {0} 매개 변수 오버로드가 Windows.Foundation.Metadata.DefaultOverloadAttribute로 장식됩니다. - - - 특성은 메서드의 한 오버로드에만 적용할 수 있습니다. - - - 네임스페이스 이름은 대소문자만 다를 수 없습니다. - - - 이름이 '{0}';인 네임스페이스가 여러 개 있습니다. 네임스페이스 이름은 Windows 런타임 대/소문자만 다를 수 없습니다. - {0} will be some user-defined keyword - - - DefaultOverload 특성 없이 여러 오버로드가 표시됨 - - - 클래스 {2}에서: {1}의 {0}-매개 변수 오버로드에는 Windows.Foundation.Metadata.DefaultOverloadAttribute로 데코레이션하여 기본 오버로드로 지정된 정확히 하나의 메서드가 있어야 합니다. - - - InAttribute 또는 OutAttribute로 표시된 매개 변수(배열 형식 아님) - - - '{0}' 메서드에 System.Runtime.InteropServices.InAttribute 또는 System.Runtime.InteropServices.OutAttribute가 있는 '{1}' 매개 변수가 있습니다. Windows 런타임은 System.Runtime.InteropServices.InAttribute 또는 System.Runtime.InteropServices.OutAttribute로 매개 변수 표시를 지원하지 않습니다. - - - System.Runtime.InteropServices.InAttribute를 제거하고 System.Runtime.InteropServices.OutAttribute를 대신 'out' 한정자로 바꾸세요. - - - ReadOnlyArray 또는 WriteOnlyArray로 표시된 비배열 매개변수 - - - 메서드 '{0}' 배열이 아닌 매개 변수 '{1}' ReadOnlyArray 특성 또는 WriteOnlyArray 특성이 있습니다. - - - Windows 런타임 ReadOnlyArray 또는 WriteOnlyArray를 사용하여 배열이 아닌 매개 변수를 표시할 수 없습니다. - - - 잘못된 인터페이스 상속됨 - - - 인터페이스가 올바른 Windows 런타임 인터페이스가 아니므로 Windows 런타임 구성 요소 형식 {0} 인터페이스 {1} 구현할 수 없습니다. - - - 정의된 공개 유형이 없습니다. - - - Windows 런타임 구성 요소에는 하나 이상의 공개 유형이 있어야 합니다. - - - 운영자 과부하 노출 - - - {0} 연산자 오버로드이므로 관리되는 형식은 Windows 런타임 연산자 오버로드를 노출할 수 없습니다. - - - 매개 변수 명명된 값 규칙 - - - {0} 메서드에 {1} 매개 변수 이름이 생성된 C#/WinRT interop에 사용된 반환 값 매개 변수 이름과 같습니다. 다른 매개 변수 이름 사용 - - - 속성에는 public getter가 있어야 합니다. - - - 속성 '{0}' public getter 메서드가 없습니다. Windows 런타임 setter 전용 속성을 지원하지 않습니다. - {0} will be some user-defined keyword - - - 참조로 전달된 매개변수 - - - 메서드 '{0}' 'ref'로 표시된 매개 변수 '{1}' 있습니다. Windows 런타임 참조 매개 변수를 사용할 수 없습니다. - - - 구조체의 Const 필드 - - - 구조 {0}에는 const 필드가 있습니다. 상수는 Windows 런타임 열거형에만 나타날 수 있습니다. - - - 구조체의 잘못된 필드 - - - 구조체 {0} {1}; 형식의 필드가 있습니다. {1} 올바른 Windows 런타임 필드 형식이 아닙니다. - - - Windows 런타임 구조의 각 필드는 UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum 또는 자체 구조일 수만 있습니다. - - - 구조체의 개인 필드 - - - 구조체 {0} public이 아닌 필드가 있습니다. 모든 필드는 Windows 런타임 구조에 대해 public이어야 합니다. - - - 빈 구조체 규칙 - - - 구조 {0} 공용 필드가 없습니다. Windows 런타임 구조체에는 하나 이상의 공용 필드가 있어야 합니다. - - - 클래스가 인터페이스를 잘못 구현함 - - - 멤버 '{2}' 없거나 public이 아니므로 클래스 '{0}' 인터페이스 '{1}' 올바르게 구현하지 않습니다. - - - 클래스가 봉인되지 않음 - - - 봉인되지 않은 형식 내보내기는 CsWinRT에서 지원되지 않습니다. 형식 {0}을 봉인된 것으로 표시하세요. - {0} will be some user-defined keyword - - - 지원되지 않는 유형 노출 - - - 멤버 '{0}' 시그니처에 '{1}' 형식이 있습니다. - {0} and {1} will be user-defined keywords - - - '{1}' 형식이 올바른 Windows 런타임 형식이 아닙니다. - {1} will be some user-defined keyword - - - 그러나 형식(또는 제네릭 매개 변수)은 올바른 Windows 런타임 형식인 인터페이스를 구현합니다. - - - 멤버 서명의 '{1} 유형을 System.Collections.Generic: {2}에서 다음 유형 중 하나로 변경하는 것이 좋습니다. - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + InAttribute 또는 OutAttribute로 표시된 배열 매개 변수 + + + '{0}' 메서드에 배열인 매개 변수 '{1}' System.Runtime.InteropServices.InAttribute 또는 System.Runtime.InteropServices.OutAttribute가 있는 매개 변수가 있습니다. + + + Windows 런타임에서 배열 매개 변수에는 ReadOnlyArray 또는 WriteOnlyArray가 있어야 합니다. + + + 이러한 특성을 제거하거나 필요한 경우 적절한 Windows 런타임 특성으로 바꾸십시오. + + + 'out'으로 표시된 배열 매개 변수 및 ReadOnlyArray + + + 메서드 '{0}' 배열이지만 ReadOnlyArray 특성이 있는 출력 매개 변수 '{1}' 있습니다. + + + Windows 런타임 출력 배열의 내용을 쓸 수 있습니다. '{1}' 특성을 제거하십시오. + + + ReadOnlyArray 및 WriteOnlyArray 모두로 표시된 배열 매개 변수 + + + '{0}' 메서드에 배열인 매개 변수 '{1}' ReadOnlyArray와 WriteOnlyArray가 둘 다 있습니다. + + + Windows 런타임에서 콘텐츠 배열 매개 변수는 읽기 또는 쓰기가 가능해야 합니다. '{1}'에서 특성 중 하나를 제거하세요. + + + 배열 매개 변수가 ReadOnlyArray 또는 WriteOnlyArray 방식으로 표시되지 않았습니다. + + + '{0}' 메서드에 배열인 매개 변수 '{1}' 있습니다. + + + Windows 런타임 배열 매개 변수의 내용은 읽기 가능하거나 쓰기 가능해야 합니다. readOnlyArray 또는 WriteOnlyArray를 '{1}' 적용하세요. + + + 클래스 생성자 규칙 + + + 클래스는 Windows 런타임에서 동일한 arity의 여러 생성자를 가질 수 없습니다. 클래스 {0}에는 여러 {1}-arity 생성자가 있습니다. + + + 네임스페이스가 기본(winmd) 네임스페이스와 분리되어 있습니다. + + + public 형식에 다른 네임스페이스와 공통 접두사를 공유하지 않는 네임스페이스('{1}')가 있습니다('{0}'). + {1} and {0} will be some user-defined keyword + + + Windows 메타데이터 파일 내의 모든 형식은 파일 이름에 포함된 네임스페이스의 하위 네임스페이스에 있어야 합니다. + "sub namespace" means a namespace defined within another namespace + + + 클래스(또는 인터페이스)가 일반적입니다. + + + 형식 {0} 제네릭이므로 Windows 런타임 형식은 제네릭일 수 없습니다. + {0} will be some user-defined keyword + + + 유효한 WinRT 유형이 아닌 들쭉날쭉한 배열로 배열 서명을 찾았습니다. + + + 메서드 {0} 시그니처에 {1} 형식의 중첩 배열이 있습니다. Windows 런타임 메서드 시그니처의 배열은 중첩될 수 없습니다. + + + 유효한 Windows 런타임 유형이 아닌 다차원 배열로 배열 서명을 찾았습니다. + + + 메서드 '{0}' 시그니처에 '{1}' 형식의 다차원 배열이 있습니다. Windows 런타임 메서드 시그니처의 배열은 1차원이어야 합니다. + + + 하나의 과부하만 기본값으로 지정해야 합니다. + + + 클래스 {2}에서: '{1}'의 여러 {0} 매개 변수 오버로드가 Windows.Foundation.Metadata.DefaultOverloadAttribute로 장식됩니다. + + + 특성은 메서드의 한 오버로드에만 적용할 수 있습니다. + + + 네임스페이스 이름은 대소문자만 다를 수 없습니다. + + + 이름이 '{0}';인 네임스페이스가 여러 개 있습니다. 네임스페이스 이름은 Windows 런타임 대/소문자만 다를 수 없습니다. + {0} will be some user-defined keyword + + + DefaultOverload 특성 없이 여러 오버로드가 표시됨 + + + 클래스 {2}에서: {1}의 {0}-매개 변수 오버로드에는 Windows.Foundation.Metadata.DefaultOverloadAttribute로 데코레이션하여 기본 오버로드로 지정된 정확히 하나의 메서드가 있어야 합니다. + + + InAttribute 또는 OutAttribute로 표시된 매개 변수(배열 형식 아님) + + + '{0}' 메서드에 System.Runtime.InteropServices.InAttribute 또는 System.Runtime.InteropServices.OutAttribute가 있는 '{1}' 매개 변수가 있습니다. Windows 런타임은 System.Runtime.InteropServices.InAttribute 또는 System.Runtime.InteropServices.OutAttribute로 매개 변수 표시를 지원하지 않습니다. + + + System.Runtime.InteropServices.InAttribute를 제거하고 System.Runtime.InteropServices.OutAttribute를 대신 'out' 한정자로 바꾸세요. + + + ReadOnlyArray 또는 WriteOnlyArray로 표시된 비배열 매개변수 + + + 메서드 '{0}' 배열이 아닌 매개 변수 '{1}' ReadOnlyArray 특성 또는 WriteOnlyArray 특성이 있습니다. + + + Windows 런타임 ReadOnlyArray 또는 WriteOnlyArray를 사용하여 배열이 아닌 매개 변수를 표시할 수 없습니다. + + + 잘못된 인터페이스 상속됨 + + + 인터페이스가 올바른 Windows 런타임 인터페이스가 아니므로 Windows 런타임 구성 요소 형식 {0} 인터페이스 {1} 구현할 수 없습니다. + + + 정의된 공개 유형이 없습니다. + + + Windows 런타임 구성 요소에는 하나 이상의 공개 유형이 있어야 합니다. + + + 운영자 과부하 노출 + + + {0} 연산자 오버로드이므로 관리되는 형식은 Windows 런타임 연산자 오버로드를 노출할 수 없습니다. + + + 매개 변수 명명된 값 규칙 + + + {0} 메서드에 {1} 매개 변수 이름이 생성된 C#/WinRT interop에 사용된 반환 값 매개 변수 이름과 같습니다. 다른 매개 변수 이름 사용 + + + 속성에는 public getter가 있어야 합니다. + + + 속성 '{0}' public getter 메서드가 없습니다. Windows 런타임 setter 전용 속성을 지원하지 않습니다. + {0} will be some user-defined keyword + + + 참조로 전달된 매개변수 + + + 메서드 '{0}' 'ref'로 표시된 매개 변수 '{1}' 있습니다. Windows 런타임 참조 매개 변수를 사용할 수 없습니다. + + + 구조체의 Const 필드 + + + 구조 {0}에는 const 필드가 있습니다. 상수는 Windows 런타임 열거형에만 나타날 수 있습니다. + + + 구조체의 잘못된 필드 + + + 구조체 {0} {1}; 형식의 필드가 있습니다. {1} 올바른 Windows 런타임 필드 형식이 아닙니다. + + + Windows 런타임 구조의 각 필드는 UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum 또는 자체 구조일 수만 있습니다. + + + 구조체의 개인 필드 + + + 구조체 {0} public이 아닌 필드가 있습니다. 모든 필드는 Windows 런타임 구조에 대해 public이어야 합니다. + + + 빈 구조체 규칙 + + + 구조 {0} 공용 필드가 없습니다. Windows 런타임 구조체에는 하나 이상의 공용 필드가 있어야 합니다. + + + 클래스가 인터페이스를 잘못 구현함 + + + 멤버 '{2}' 없거나 public이 아니므로 클래스 '{0}' 인터페이스 '{1}' 올바르게 구현하지 않습니다. + + + 클래스가 봉인되지 않음 + + + 봉인되지 않은 형식 내보내기는 CsWinRT에서 지원되지 않습니다. 형식 {0}을 봉인된 것으로 표시하세요. + {0} will be some user-defined keyword + + + 지원되지 않는 유형 노출 + + + 멤버 '{0}' 시그니처에 '{1}' 형식이 있습니다. + {0} and {1} will be user-defined keywords + + + '{1}' 형식이 올바른 Windows 런타임 형식이 아닙니다. + {1} will be some user-defined keyword + + + 그러나 형식(또는 제네릭 매개 변수)은 올바른 Windows 런타임 형식인 인터페이스를 구현합니다. + + + 멤버 서명의 '{1} 유형을 System.Collections.Generic: {2}에서 다음 유형 중 하나로 변경하는 것이 좋습니다. + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/pt-BR/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/pt-BR/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/pt-BR/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/pt-BR/CsWinRTDiagnosticStrings.resx index 5c54d7e99..dd2478b24 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/pt-BR/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/pt-BR/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Parâmetro de matriz marcado como InAttribute ou OutAttribute - - - O '{0}' tem parâmetro '{1}' que é uma matriz e que tem Um System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute. - - - No Windows Runtime, os parâmetros de matriz devem ter ReadOnlyArray ou WriteOnlyArray. - - - Remova esses atributos ou substitua-os pelo atributo Windows Runtime apropriado, se necessário. - - - Parâmetro de matriz marcado como `out` e ReadOnlyArray - - - O '{0}' tem um parâmetro de '{1}' que é uma matriz, mas que tem o atributo ReadOnlyArray. - - - No Windows Runtime, o conteúdo das matrizes de saída é gravável. Remova o atributo de '{1}'. - - - Parâmetro de matriz marcado como ReadOnlyArray e WriteOnlyArray - - - O '{0}' tem parâmetro '{1}' que é uma matriz e que tem ReadOnlyArray e WriteOnlyArray. - - - No Windows Runtime, os parâmetros da matriz de conteúdo devem ser legívels ou graváveis. Remova um dos atributos do '{1}'. - - - Parâmetro de matriz não marcado como ReadOnlyArray ou WriteOnlyArray - - - O '{0}' tem parâmetro '{1}' que é uma matriz. - - - No Windows Runtime, o conteúdo dos parâmetros da matriz deve ser legível ou gravável; aplique ReadOnlyArray ou WriteOnlyArray ao '{1}'. - - - Regra de Construtor de Classe - - - Classes não podem ter vários construtores do mesmo arity no Windows Runtime, a classe {0} tem vários construtores {1}-arity - - - Namespace não contíguo com o namespace principal (winmd) - - - Um tipo público tem um namespace ('{1}') que não compartilha prefixo comum com outros namespaces ('{0}'). - {1} and {0} will be some user-defined keyword - - - Todos os tipos em um arquivo de Metadados do Windows devem existir em um sub namespace do namespace implícito pelo nome do arquivo. - "sub namespace" means a namespace defined within another namespace - - - A classe (ou interface) é genérica - - - O {0} tipo é genérico, Windows Runtime tipos não podem ser genéricos - {0} will be some user-defined keyword - - - Assinatura de matriz encontrada com matriz irregular, que não é um tipo WinRT válido - - - O {0} tem uma matriz aninhada do tipo {1} em sua assinatura; matrizes em Windows Runtime assinatura de método não podem ser aninhadas - - - Assinatura de matriz encontrada com matriz multidimensional, que não é um tipo Windows Runtime válido - - - O '{0}' tem uma matriz multidimensional do tipo '{1}' em sua assinatura; matrizes em Windows Runtime assinaturas de método devem ser unidimensionais - - - Apenas uma sobrecarga deve ser designada como padrão - - - Na classe {2}: várias sobrecargas de {0} parâmetro(s) de '{1}' são decoradas com Windows.Foundation.Metadata.DefaultOverloadAttribute. - - - O atributo só pode ser aplicado a uma sobrecarga do método. - - - Os nomes de namespace não podem diferir apenas por letras maiúsculas e minúsculas - - - Vários namespaces encontrados com o nome '{0}'; nomes de namespace não podem diferir somente por maiúsculas e minúsculas no Windows Runtime - {0} will be some user-defined keyword - - - Várias sobrecargas vistas sem o atributo DefaultOverload - - - Na classe {2}: as sobrecargas de {0} parâmetro(s) de {1} devem ter exatamente um método especificado como a sobrecarga padrão decorando-a com Windows.Foundation.Metadata.DefaultOverloadAttribute - - - Parâmetro (não tipo de matriz) marcado como InAttribute ou OutAttribute - - - O método '{0}' tem o parâmetro '{1}' com um System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute. O Windows Runtime não oferece suporte à marcação de parâmetros com System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute. - - - Considere remover System.Runtime.InteropServices.InAttribute e substituir System.Runtime.InteropServices.OutAttribute pelo modificador 'out'. - - - Parâmetro não matriz marcado com ReadOnlyArray ou WriteOnlyArray - - - O '{0}' tem parâmetro '{1}' que não é uma matriz e que tem um atributo ReadOnlyArray ou um atributo WriteOnlyArray. - - - Windows Runtime não dá suporte à marcação de parâmetros que não são de matriz com ReadOnlyArray ou WriteOnlyArray. - - - Interface Inválida Herdada - - - Windows Runtime tipo de componente {0} não pode implementar a interface {1}, pois a interface não é uma interface Windows Runtime interface válida - - - Nenhum tipo público definido - - - Windows Runtime componentes devem ter pelo menos um tipo público - - - Sobrecarga do operador exposta - - - {0} é uma sobrecarga de operador, os tipos gerenciados não podem expor sobrecargas de operador no Windows Runtime - - - Regra de Valor Nomeado do Parâmetro - - - O nome do {1} no método {0} é igual ao nome do parâmetro de valor de retorno usado na interoperabilidade C#/WinRT gerada; usar um nome de parâmetro diferente - - - A propriedade deve ter getter público - - - A '{0}' não tem um método getter público. Windows Runtime não dá suporte a propriedades somente setter. - {0} will be some user-defined keyword - - - Parâmetro passado por referência - - - O '{0}' tem parâmetro '{1}' marcado como 'ref'; parâmetros de referência não são permitidos Windows Runtime - - - Campo const em struct - - - Estrutura {0} tem campo const - constantes só podem aparecer em Windows Runtime enumerações. - - - Campo inválido no struct - - - Estrutura {0} tem campo do tipo {1}; {1} não é um tipo de campo Windows Runtime válido. - - - Cada campo em uma estrutura Windows Runtime só pode ser UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Único, Duplo, Booliano, Cadeia de caracteres, Enum ou uma estrutura em si. - - - Campo privado no struct - - - O {0} estrutura tem um campo não público. Todos os campos devem ser públicos para Windows Runtime estruturas. - - - Regra de struct vazia - - - O {0} não contém campos públicos. Windows Runtime estruturas devem conter pelo menos um campo público. - - - A classe implementa incorretamente uma interface - - - O '{0}' classe não implementa corretamente a interface '{1}' porque o '{2}' membro está ausente ou não é público - - - A classe não está selada - - - Não há suporte para a exportação de tipos não selados no CsWinRT. marque o tipo {0} como selado - {0} will be some user-defined keyword - - - Expondo tipo sem suporte - - - O membro '{0}' tem o tipo '{1}' em sua assinatura. - {0} and {1} will be user-defined keywords - - - O tipo '{1}' não é um tipo Windows Runtime válido. - {1} will be some user-defined keyword - - - No entanto, o tipo (ou seus parâmetros genéricos) implementam interfaces que são tipos Windows Runtime válidos. - - - Considere alterar o tipo '{1} na assinatura do membro para um dos seguintes tipos de System.Collections.Generic: {2}. - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Parâmetro de matriz marcado como InAttribute ou OutAttribute + + + O '{0}' tem parâmetro '{1}' que é uma matriz e que tem Um System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute. + + + No Windows Runtime, os parâmetros de matriz devem ter ReadOnlyArray ou WriteOnlyArray. + + + Remova esses atributos ou substitua-os pelo atributo Windows Runtime apropriado, se necessário. + + + Parâmetro de matriz marcado como `out` e ReadOnlyArray + + + O '{0}' tem um parâmetro de '{1}' que é uma matriz, mas que tem o atributo ReadOnlyArray. + + + No Windows Runtime, o conteúdo das matrizes de saída é gravável. Remova o atributo de '{1}'. + + + Parâmetro de matriz marcado como ReadOnlyArray e WriteOnlyArray + + + O '{0}' tem parâmetro '{1}' que é uma matriz e que tem ReadOnlyArray e WriteOnlyArray. + + + No Windows Runtime, os parâmetros da matriz de conteúdo devem ser legívels ou graváveis. Remova um dos atributos do '{1}'. + + + Parâmetro de matriz não marcado como ReadOnlyArray ou WriteOnlyArray + + + O '{0}' tem parâmetro '{1}' que é uma matriz. + + + No Windows Runtime, o conteúdo dos parâmetros da matriz deve ser legível ou gravável; aplique ReadOnlyArray ou WriteOnlyArray ao '{1}'. + + + Regra de Construtor de Classe + + + Classes não podem ter vários construtores do mesmo arity no Windows Runtime, a classe {0} tem vários construtores {1}-arity + + + Namespace não contíguo com o namespace principal (winmd) + + + Um tipo público tem um namespace ('{1}') que não compartilha prefixo comum com outros namespaces ('{0}'). + {1} and {0} will be some user-defined keyword + + + Todos os tipos em um arquivo de Metadados do Windows devem existir em um sub namespace do namespace implícito pelo nome do arquivo. + "sub namespace" means a namespace defined within another namespace + + + A classe (ou interface) é genérica + + + O {0} tipo é genérico, Windows Runtime tipos não podem ser genéricos + {0} will be some user-defined keyword + + + Assinatura de matriz encontrada com matriz irregular, que não é um tipo WinRT válido + + + O {0} tem uma matriz aninhada do tipo {1} em sua assinatura; matrizes em Windows Runtime assinatura de método não podem ser aninhadas + + + Assinatura de matriz encontrada com matriz multidimensional, que não é um tipo Windows Runtime válido + + + O '{0}' tem uma matriz multidimensional do tipo '{1}' em sua assinatura; matrizes em Windows Runtime assinaturas de método devem ser unidimensionais + + + Apenas uma sobrecarga deve ser designada como padrão + + + Na classe {2}: várias sobrecargas de {0} parâmetro(s) de '{1}' são decoradas com Windows.Foundation.Metadata.DefaultOverloadAttribute. + + + O atributo só pode ser aplicado a uma sobrecarga do método. + + + Os nomes de namespace não podem diferir apenas por letras maiúsculas e minúsculas + + + Vários namespaces encontrados com o nome '{0}'; nomes de namespace não podem diferir somente por maiúsculas e minúsculas no Windows Runtime + {0} will be some user-defined keyword + + + Várias sobrecargas vistas sem o atributo DefaultOverload + + + Na classe {2}: as sobrecargas de {0} parâmetro(s) de {1} devem ter exatamente um método especificado como a sobrecarga padrão decorando-a com Windows.Foundation.Metadata.DefaultOverloadAttribute + + + Parâmetro (não tipo de matriz) marcado como InAttribute ou OutAttribute + + + O método '{0}' tem o parâmetro '{1}' com um System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute. O Windows Runtime não oferece suporte à marcação de parâmetros com System.Runtime.InteropServices.InAttribute ou System.Runtime.InteropServices.OutAttribute. + + + Considere remover System.Runtime.InteropServices.InAttribute e substituir System.Runtime.InteropServices.OutAttribute pelo modificador 'out'. + + + Parâmetro não matriz marcado com ReadOnlyArray ou WriteOnlyArray + + + O '{0}' tem parâmetro '{1}' que não é uma matriz e que tem um atributo ReadOnlyArray ou um atributo WriteOnlyArray. + + + Windows Runtime não dá suporte à marcação de parâmetros que não são de matriz com ReadOnlyArray ou WriteOnlyArray. + + + Interface Inválida Herdada + + + Windows Runtime tipo de componente {0} não pode implementar a interface {1}, pois a interface não é uma interface Windows Runtime interface válida + + + Nenhum tipo público definido + + + Windows Runtime componentes devem ter pelo menos um tipo público + + + Sobrecarga do operador exposta + + + {0} é uma sobrecarga de operador, os tipos gerenciados não podem expor sobrecargas de operador no Windows Runtime + + + Regra de Valor Nomeado do Parâmetro + + + O nome do {1} no método {0} é igual ao nome do parâmetro de valor de retorno usado na interoperabilidade C#/WinRT gerada; usar um nome de parâmetro diferente + + + A propriedade deve ter getter público + + + A '{0}' não tem um método getter público. Windows Runtime não dá suporte a propriedades somente setter. + {0} will be some user-defined keyword + + + Parâmetro passado por referência + + + O '{0}' tem parâmetro '{1}' marcado como 'ref'; parâmetros de referência não são permitidos Windows Runtime + + + Campo const em struct + + + Estrutura {0} tem campo const - constantes só podem aparecer em Windows Runtime enumerações. + + + Campo inválido no struct + + + Estrutura {0} tem campo do tipo {1}; {1} não é um tipo de campo Windows Runtime válido. + + + Cada campo em uma estrutura Windows Runtime só pode ser UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Único, Duplo, Booliano, Cadeia de caracteres, Enum ou uma estrutura em si. + + + Campo privado no struct + + + O {0} estrutura tem um campo não público. Todos os campos devem ser públicos para Windows Runtime estruturas. + + + Regra de struct vazia + + + O {0} não contém campos públicos. Windows Runtime estruturas devem conter pelo menos um campo público. + + + A classe implementa incorretamente uma interface + + + O '{0}' classe não implementa corretamente a interface '{1}' porque o '{2}' membro está ausente ou não é público + + + A classe não está selada + + + Não há suporte para a exportação de tipos não selados no CsWinRT. marque o tipo {0} como selado + {0} will be some user-defined keyword + + + Expondo tipo sem suporte + + + O membro '{0}' tem o tipo '{1}' em sua assinatura. + {0} and {1} will be user-defined keywords + + + O tipo '{1}' não é um tipo Windows Runtime válido. + {1} will be some user-defined keyword + + + No entanto, o tipo (ou seus parâmetros genéricos) implementam interfaces que são tipos Windows Runtime válidos. + + + Considere alterar o tipo '{1} na assinatura do membro para um dos seguintes tipos de System.Collections.Generic: {2}. + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/ru-RU/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ru-RU/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/ru-RU/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ru-RU/CsWinRTDiagnosticStrings.resx index ff7d43835..36495b174 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/ru-RU/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ru-RU/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Параметр массива помечен как InAttribute или OutAttribute - - - Метод '{0}' имеет параметр '{1}', который является массивом и имеет атрибут System.Runtime.InteropServices.InAttribute или System.Runtime.InteropServices.OutAttribute. - - - В среде выполнения Windows параметры массива должны иметь метку ReadOnlyArray или WriteOnlyArray. - - - Удалите эти атрибуты или замените их соответствующим атрибутом среды выполнения Windows при необходимости. - - - Параметр массива помечен как out и ReadOnlyArray - - - Метод '{0}' имеет выходной '{1}', который является массивом, но имеет атрибут ReadOnlyArray. - - - В среда выполнения Windows записи содержимое выходных массивов. Удалите атрибут из '{1}'. - - - Параметр массива помечен одновременно как ReadOnlyArray и WriteOnlyArray - - - Метод '{0}' имеет параметр '{1}', который является массивом и имеет readOnlyArray и WriteOnlyArray. - - - В среда выполнения Windows параметры массива содержимого должны быть доступны для чтения или записи. Удалите один из атрибутов из '{1}'. - - - Параметр массива не помечен как ReadOnlyArray или WriteOnlyArray - - - Метод '{0}' имеет параметр '{1}', который является массивом. - - - В среде выполнения Windows содержимое параметров массива должно быть доступно для чтения или записи. Примените ReadOnlyArray или WriteOnlyArray к "{1}". - - - Правило конструктора классов - - - Классы не могут содержать несколько конструкторов с одинаковой арностью в среде выполнения Windows. Класс {0} содержит несколько конструкторов арности {1} - - - Пространство имен отсоединено от основного пространства имен (winmd) - - - Открытый тип имеет пространство имен ('{1}'), которое не имеет общего префикса с другими пространствами имен ('{0}'). - {1} and {0} will be some user-defined keyword - - - Все типы в файле метаданных Windows должны существовать во вложенном пространстве имен пространства имен, которое соответствует имени файла. - "sub namespace" means a namespace defined within another namespace - - - Класс (или интерфейс) является универсальным - - - Тип {0} является универсальным. Типы среды выполнения Windows не могут быть универсальными - {0} will be some user-defined keyword - - - Обнаружена подпись с массивом массивов, который не является допустимым типом WinRT - - - Метод {0} содержит вложенный массив типа {1} в подписи. Массивы в подписи метода среды выполнения Windows не могут быть вложенными - - - Обнаружена подпись массива с многомерным массивом, который не является допустимым типом среды выполнения Windows - - - Метод "{0}" содержит многомерный массив типа {1} в подписи. Массивы в подписях методов среды выполнения Windows должны быть одномерными - - - По умолчанию должна быть назначена только одна перегрузка - - - В классе {2}: множественные перегрузки "{1}" параметра {0} снабжены атрибутом Windows.Foundation.Metadata.DefaultOverloadAttribute. - - - Атрибут может применяться только к одной перегрузке метода. - - - Имена пространств имен не могут отличаться только регистром - - - Найдено несколько пространств имен с именем "{0}". Имена пространств имен не могут отличаться только регистром в среде выполнения Windows - {0} will be some user-defined keyword - - - Обнаружено несколько перегрузок без атрибута DefaultOverload - - - В классе {2}: перегрузки {1} параметра {0} должны использовать только один метод, указанный в качестве перегрузки по умолчанию, путем добавления Windows.Foundation.Metadata.DefaultOverloadAttribute - - - Параметр (не относящийся к массиву) помечен как InAttribute или OutAttribute - - - Метод "{0}" содержит параметр "{1}" с System.Runtime.InteropServices.InAttribute или System.Runtime.InteropServices.OutAttribute. Среда выполнения Windows не поддерживает маркировку параметров с помощью System.Runtime.InteropServices.InAttribute или System.Runtime.InteropServices.OutAttribute. - - - Рассмотрите возможность удаления System.Runtime.InteropServices.InAttribute и замены System.Runtime.InteropServices.OutAttribute модификатором "out". - - - Параметр, не относящийся к массиву, помечен как ReadOnlyArray или WriteOnlyArray - - - Метод '{0}' имеет параметр '{1}', который не является массивом и имеет либо атрибут ReadOnlyArray, либо атрибут WriteOnlyArray. - - - Среда выполнения Windows не поддерживает маркировку параметров, не относящихся к массиву, с помощью ReadOnlyArray или WriteOnlyArray. - - - Унаследованный интерфейс недопустим - - - Тип компонента среды выполнения Windows {0} не может реализовать интерфейс {1}, так как интерфейс не является допустимым интерфейсом среды выполнения Windows - - - Общедоступные типы не определены - - - Компоненты среды выполнения Windows должны содержать по крайней мере один общедоступный тип - - - Предоставлена перегрузка оператора - - - {0} является перегрузкой оператора. Управляемые типы не могут предоставлять доступ к перегрузкам операторов в среде выполнения Windows - - - Правило именованного значения параметра - - - Имя параметра {1} в методе {0} совпадает с именем параметра возвращаемого значения, используемым в созданном взаимодействии C#/WinRT. Примените другое имя параметра - - - Свойство должно иметь общедоступный метод получения - - - Свойство "{0}" не имеет общедоступного метода получения. Среда выполнения Windows не поддерживает свойства только метода задания. - {0} will be some user-defined keyword - - - Параметр, переданный ссылкой - - - Метод "{0}" содержит параметр "{1}", помеченный как "ref". Ссылочные параметры не разрешены в среде выполнения Windows - - - Поле константы в структуре - - - Структура {0} содержит поле константы — константы могут отображаться только в перечислениях среды выполнения Windows. - - - Недопустимое поле в структуре - - - Структура {0} имеет поле типа {1}; {1} не является допустимым типом среда выполнения Windows поля. - - - Каждое поле в структуре среды выполнения Windows может быть только типом UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum или самостоятельной структурой. - - - Частное поле в структуре - - - Структура {0} содержит поле, не являющееся общедоступным. Для структур среды выполнения Windows все поля должны быть общедоступными. - - - Правило пустой структуры - - - Структура {0} не содержит общедоступных полей. Структуры среды выполнения Windows должны содержать по крайней мере одно общедоступное поле. - - - Класс неправильно реализует интерфейс - - - Класс '{0}' неправильно реализует интерфейс '{1}', так как '{2}' элемент отсутствует или не является общедоступным - - - Класс не запечатан - - - Экспорт незапечатанных типов не поддерживается в CsWinRT. Пометьте тип {0} как запечатанный - {0} will be some user-defined keyword - - - Предоставление неподдерживаемого типа - - - Элемент '{0}' имеет тип, '{1}' сигнатуре. - {0} and {1} will be user-defined keywords - - - Тип '{1}' не является допустимым среда выполнения Windows типа. - {1} will be some user-defined keyword - - - Однако тип (или его универсальные параметры) реализует интерфейсы, которые являются допустимыми типами среды выполнения Windows. - - - Попробуйте изменить тип "{1}" в подписи элемента на один из следующих типов из System.Collections.Generic: {2}. - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Параметр массива помечен как InAttribute или OutAttribute + + + Метод '{0}' имеет параметр '{1}', который является массивом и имеет атрибут System.Runtime.InteropServices.InAttribute или System.Runtime.InteropServices.OutAttribute. + + + В среде выполнения Windows параметры массива должны иметь метку ReadOnlyArray или WriteOnlyArray. + + + Удалите эти атрибуты или замените их соответствующим атрибутом среды выполнения Windows при необходимости. + + + Параметр массива помечен как out и ReadOnlyArray + + + Метод '{0}' имеет выходной '{1}', который является массивом, но имеет атрибут ReadOnlyArray. + + + В среда выполнения Windows записи содержимое выходных массивов. Удалите атрибут из '{1}'. + + + Параметр массива помечен одновременно как ReadOnlyArray и WriteOnlyArray + + + Метод '{0}' имеет параметр '{1}', который является массивом и имеет readOnlyArray и WriteOnlyArray. + + + В среда выполнения Windows параметры массива содержимого должны быть доступны для чтения или записи. Удалите один из атрибутов из '{1}'. + + + Параметр массива не помечен как ReadOnlyArray или WriteOnlyArray + + + Метод '{0}' имеет параметр '{1}', который является массивом. + + + В среде выполнения Windows содержимое параметров массива должно быть доступно для чтения или записи. Примените ReadOnlyArray или WriteOnlyArray к "{1}". + + + Правило конструктора классов + + + Классы не могут содержать несколько конструкторов с одинаковой арностью в среде выполнения Windows. Класс {0} содержит несколько конструкторов арности {1} + + + Пространство имен отсоединено от основного пространства имен (winmd) + + + Открытый тип имеет пространство имен ('{1}'), которое не имеет общего префикса с другими пространствами имен ('{0}'). + {1} and {0} will be some user-defined keyword + + + Все типы в файле метаданных Windows должны существовать во вложенном пространстве имен пространства имен, которое соответствует имени файла. + "sub namespace" means a namespace defined within another namespace + + + Класс (или интерфейс) является универсальным + + + Тип {0} является универсальным. Типы среды выполнения Windows не могут быть универсальными + {0} will be some user-defined keyword + + + Обнаружена подпись с массивом массивов, который не является допустимым типом WinRT + + + Метод {0} содержит вложенный массив типа {1} в подписи. Массивы в подписи метода среды выполнения Windows не могут быть вложенными + + + Обнаружена подпись массива с многомерным массивом, который не является допустимым типом среды выполнения Windows + + + Метод "{0}" содержит многомерный массив типа {1} в подписи. Массивы в подписях методов среды выполнения Windows должны быть одномерными + + + По умолчанию должна быть назначена только одна перегрузка + + + В классе {2}: множественные перегрузки "{1}" параметра {0} снабжены атрибутом Windows.Foundation.Metadata.DefaultOverloadAttribute. + + + Атрибут может применяться только к одной перегрузке метода. + + + Имена пространств имен не могут отличаться только регистром + + + Найдено несколько пространств имен с именем "{0}". Имена пространств имен не могут отличаться только регистром в среде выполнения Windows + {0} will be some user-defined keyword + + + Обнаружено несколько перегрузок без атрибута DefaultOverload + + + В классе {2}: перегрузки {1} параметра {0} должны использовать только один метод, указанный в качестве перегрузки по умолчанию, путем добавления Windows.Foundation.Metadata.DefaultOverloadAttribute + + + Параметр (не относящийся к массиву) помечен как InAttribute или OutAttribute + + + Метод "{0}" содержит параметр "{1}" с System.Runtime.InteropServices.InAttribute или System.Runtime.InteropServices.OutAttribute. Среда выполнения Windows не поддерживает маркировку параметров с помощью System.Runtime.InteropServices.InAttribute или System.Runtime.InteropServices.OutAttribute. + + + Рассмотрите возможность удаления System.Runtime.InteropServices.InAttribute и замены System.Runtime.InteropServices.OutAttribute модификатором "out". + + + Параметр, не относящийся к массиву, помечен как ReadOnlyArray или WriteOnlyArray + + + Метод '{0}' имеет параметр '{1}', который не является массивом и имеет либо атрибут ReadOnlyArray, либо атрибут WriteOnlyArray. + + + Среда выполнения Windows не поддерживает маркировку параметров, не относящихся к массиву, с помощью ReadOnlyArray или WriteOnlyArray. + + + Унаследованный интерфейс недопустим + + + Тип компонента среды выполнения Windows {0} не может реализовать интерфейс {1}, так как интерфейс не является допустимым интерфейсом среды выполнения Windows + + + Общедоступные типы не определены + + + Компоненты среды выполнения Windows должны содержать по крайней мере один общедоступный тип + + + Предоставлена перегрузка оператора + + + {0} является перегрузкой оператора. Управляемые типы не могут предоставлять доступ к перегрузкам операторов в среде выполнения Windows + + + Правило именованного значения параметра + + + Имя параметра {1} в методе {0} совпадает с именем параметра возвращаемого значения, используемым в созданном взаимодействии C#/WinRT. Примените другое имя параметра + + + Свойство должно иметь общедоступный метод получения + + + Свойство "{0}" не имеет общедоступного метода получения. Среда выполнения Windows не поддерживает свойства только метода задания. + {0} will be some user-defined keyword + + + Параметр, переданный ссылкой + + + Метод "{0}" содержит параметр "{1}", помеченный как "ref". Ссылочные параметры не разрешены в среде выполнения Windows + + + Поле константы в структуре + + + Структура {0} содержит поле константы — константы могут отображаться только в перечислениях среды выполнения Windows. + + + Недопустимое поле в структуре + + + Структура {0} имеет поле типа {1}; {1} не является допустимым типом среда выполнения Windows поля. + + + Каждое поле в структуре среды выполнения Windows может быть только типом UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum или самостоятельной структурой. + + + Частное поле в структуре + + + Структура {0} содержит поле, не являющееся общедоступным. Для структур среды выполнения Windows все поля должны быть общедоступными. + + + Правило пустой структуры + + + Структура {0} не содержит общедоступных полей. Структуры среды выполнения Windows должны содержать по крайней мере одно общедоступное поле. + + + Класс неправильно реализует интерфейс + + + Класс '{0}' неправильно реализует интерфейс '{1}', так как '{2}' элемент отсутствует или не является общедоступным + + + Класс не запечатан + + + Экспорт незапечатанных типов не поддерживается в CsWinRT. Пометьте тип {0} как запечатанный + {0} will be some user-defined keyword + + + Предоставление неподдерживаемого типа + + + Элемент '{0}' имеет тип, '{1}' сигнатуре. + {0} and {1} will be user-defined keywords + + + Тип '{1}' не является допустимым среда выполнения Windows типа. + {1} will be some user-defined keyword + + + Однако тип (или его универсальные параметры) реализует интерфейсы, которые являются допустимыми типами среды выполнения Windows. + + + Попробуйте изменить тип "{1}" в подписи элемента на один из следующих типов из System.Collections.Generic: {2}. + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/zh-CN/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-CN/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/zh-CN/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-CN/CsWinRTDiagnosticStrings.resx index b20f79e9f..ed41a155d 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/zh-CN/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-CN/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 标记为 InAttribute 或 OutAttribute 的数组参数 - - - 方法'{0}'具有作为数组的参数 '{1}',该参数具有 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute。 - - - 在 Windows 运行时中,数组参数必须具有 ReadOnlyArray 或 WriteOnlyArray。 - - - 如有必要,请删除这些属性或将其替换为适当的Windows 运行时属性。 - - - 标记为‘out’和 ReadOnlyArray 的数组参数 - - - 方法‘{0}’为具有输出参数‘{1}’的数组,但具有 ReadOnlyArray 属性。 - - - 在 Windows 运行时中,输出数组的内容是可写入的。请从‘{1}’中删除属性。 - - - 数组参数标记为 ReadOnlyArray 和 WriteOnlyArray - - - 方法‘{0}’为具有参数‘{1}’的数组,同时具有 ReadOnlyArray 和 WriteOnlyArray。 - - - 在 Windows 运行时中,内容数组参数必须可读或可写,请从‘{1}’中删除其中一个属性。 - - - 数组参数未标记为 ReadOnlyArray 或 WriteOnlyArray 方式 - - - 方法‘{0}’为具有参数‘{1}’的数组。 - - - 在 Windows 运行时中,数组参数的内容必须可读或可写; 请将 ReadOnlyArray 或 WriteOnlyArray 应用于‘{1}’。 - - - 类构造函数规则 - - - 类不能在 Windows 运行时中具有多个同一性的构造函数,类 {0} 具有多个 {1}-性构造函数 - - - 命名空间与主 (winmd) 命名空间不相互连接 - - - 公共类型具有一个命名空间 (‘{1}’),该命名空间与其他命名空间 (‘{0}’) 不共享公共前缀。 - {1} and {0} will be some user-defined keyword - - - Windows 元数据文件中的所有类型都必须存在于该文件名隐含的命名空间的子命名空间中。 - "sub namespace" means a namespace defined within another namespace - - - 类 (或接口) 为泛型 - - - 类型 {0} 为泛型,Windows 运行时类型不能为泛型 - {0} will be some user-defined keyword - - - 发现数组签名有锯齿状阵列,这不是有效的WinRT类型 - - - 方法 {0} 的签名中具有 {1} 类型的嵌套数组; 无法嵌套 Windows 运行时方法签名中的数组 - - - 使用多维数组找到数组签名,该数组不是有效的Windows 运行时类型 - - - 方法‘{0}’的签名中具有类型为‘{1}’的多维数组; Windows 运行时方法签名中的数组必须是一维的 - - - 默认情况下只应指定一个重载 - - - 在类 {2} 中;‘{1}’的多个 {0}-参数重载使用 Windows.Foundation.Metadata.DefaultOverloadAttribute 进行修饰。 - - - 该属性只能应用于方法的一个重载。 - - - 命名空间名称不能仅因大小写而异 - - - 找到名称为‘{0}’的多个名称空间; 在Windows 运行时中,名称空间的名称不能只因大小写而不同 - {0} will be some user-defined keyword - - - 在没有 DefaultOverload 属性的情况下看到多个重载 - - - 在类 {2}: {1} 的 {0}-参数重载必须通过使用 Windows.Foundation.Metadata.DefaultOverloadAttribute 对其进行修饰,将其指定为默认重载 - - - 标记为 InAttribute 或 OutAttribute 的参数 (非数组类型) - - - 方法‘{0}’具有带 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute 的参数‘{1}’。Windows 运行时不支持使用 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute 标记参数。 - - - 请考虑删除 System.Runtime.InteropServices.InAttribute,并将 System.Runtime.InteropServices.OutAttribute 替换为‘out’修饰符。 - - - 标有 ReadOnlyArray 或 WriteOnlyArray 的非数组参数 - - - 方法‘{0}’具有不为数组的参数‘{1},并且其具有 ReadOnlyArray 特性或 WriteOnlyArray 特性。 - - - Windows 运行时不支持使用 ReadOnlyArray 或 WriteOnlyArray 标记非数组参数。 - - - 继承的接口无效 - - - Windows 运行时组件类型{0}无法实现接口{1},因为该接口不是有效的Windows 运行时接口 - - - 未定义公共类型 - - - Windows 运行时组件必须至少有一个公共类型 - - - 运算符重载已公开 - - - {0} 运算符重载,托管类型无法在 Windows 运行时中公开运算符重载 - - - 参数命名值规则 - - - 方法{0}中{1}的参数名称与生成的 C#/WinRT 互操作中使用的返回值参数名称相同;使用其他参数名称 - - - 属性必须具有公共 getter - - - 属性'{0}'没有公共 getter 方法。Windows 运行时不支持仅 setter 属性。 - {0} will be some user-defined keyword - - - 通过引用传递的参数 - - - 方法‘{0}’具有标记为‘ref’的参数‘{1}’; Windows 运行时中不允许使用引用参数 - - - 结构中的常量字段 - - - 结构{0}具有常量字段 - 常量只能出现在Windows 运行时枚举上。 - - - 结构中的字段无效 - - - 结构{0}具有{1}类型的字段;{1}不是有效的Windows 运行时字段类型。 - - - Windows 运行时结构中的每个字段只能是 UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、Single、Double、Boolean、String、Enum 或其自身的结构。 - - - 结构中的专用字段 - - - 结构 {0} 具有非公共字段。对于 Windows 运行时结构,所有字段都必须为公共字段。 - - - 空结构规则 - - - 结构{0}不包含公共字段。Windows 运行时结构必须至少包含一个公共字段。 - - - 类错误地实现接口 - - - 类‘{0}’未正确实现接口‘{1}’,因为缺少成员‘{2}’或非公开 - - - 类以解封 - - - CsWinRT 中不支持导出未密封的类型,请将类型{0}标记为密封 - {0} will be some user-defined keyword - - - 公开不受支持的类型 - - - 成员‘{0}’在其签名中具有类型‘{1}’。 - {0} and {1} will be user-defined keywords - - - 类型'{1}'不是有效的Windows 运行时类型。 - {1} will be some user-defined keyword - - - 但是,类型 (或其泛型参数) 实现的接口是有效的 Windows 运行时类型。 - - - 请考虑将成员签名中的类型‘{1} 更改为 System.Collections.Generic 中的以下类型之一: {2}。 - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 标记为 InAttribute 或 OutAttribute 的数组参数 + + + 方法'{0}'具有作为数组的参数 '{1}',该参数具有 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute。 + + + 在 Windows 运行时中,数组参数必须具有 ReadOnlyArray 或 WriteOnlyArray。 + + + 如有必要,请删除这些属性或将其替换为适当的Windows 运行时属性。 + + + 标记为‘out’和 ReadOnlyArray 的数组参数 + + + 方法‘{0}’为具有输出参数‘{1}’的数组,但具有 ReadOnlyArray 属性。 + + + 在 Windows 运行时中,输出数组的内容是可写入的。请从‘{1}’中删除属性。 + + + 数组参数标记为 ReadOnlyArray 和 WriteOnlyArray + + + 方法‘{0}’为具有参数‘{1}’的数组,同时具有 ReadOnlyArray 和 WriteOnlyArray。 + + + 在 Windows 运行时中,内容数组参数必须可读或可写,请从‘{1}’中删除其中一个属性。 + + + 数组参数未标记为 ReadOnlyArray 或 WriteOnlyArray 方式 + + + 方法‘{0}’为具有参数‘{1}’的数组。 + + + 在 Windows 运行时中,数组参数的内容必须可读或可写; 请将 ReadOnlyArray 或 WriteOnlyArray 应用于‘{1}’。 + + + 类构造函数规则 + + + 类不能在 Windows 运行时中具有多个同一性的构造函数,类 {0} 具有多个 {1}-性构造函数 + + + 命名空间与主 (winmd) 命名空间不相互连接 + + + 公共类型具有一个命名空间 (‘{1}’),该命名空间与其他命名空间 (‘{0}’) 不共享公共前缀。 + {1} and {0} will be some user-defined keyword + + + Windows 元数据文件中的所有类型都必须存在于该文件名隐含的命名空间的子命名空间中。 + "sub namespace" means a namespace defined within another namespace + + + 类 (或接口) 为泛型 + + + 类型 {0} 为泛型,Windows 运行时类型不能为泛型 + {0} will be some user-defined keyword + + + 发现数组签名有锯齿状阵列,这不是有效的WinRT类型 + + + 方法 {0} 的签名中具有 {1} 类型的嵌套数组; 无法嵌套 Windows 运行时方法签名中的数组 + + + 使用多维数组找到数组签名,该数组不是有效的Windows 运行时类型 + + + 方法‘{0}’的签名中具有类型为‘{1}’的多维数组; Windows 运行时方法签名中的数组必须是一维的 + + + 默认情况下只应指定一个重载 + + + 在类 {2} 中;‘{1}’的多个 {0}-参数重载使用 Windows.Foundation.Metadata.DefaultOverloadAttribute 进行修饰。 + + + 该属性只能应用于方法的一个重载。 + + + 命名空间名称不能仅因大小写而异 + + + 找到名称为‘{0}’的多个名称空间; 在Windows 运行时中,名称空间的名称不能只因大小写而不同 + {0} will be some user-defined keyword + + + 在没有 DefaultOverload 属性的情况下看到多个重载 + + + 在类 {2}: {1} 的 {0}-参数重载必须通过使用 Windows.Foundation.Metadata.DefaultOverloadAttribute 对其进行修饰,将其指定为默认重载 + + + 标记为 InAttribute 或 OutAttribute 的参数 (非数组类型) + + + 方法‘{0}’具有带 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute 的参数‘{1}’。Windows 运行时不支持使用 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute 标记参数。 + + + 请考虑删除 System.Runtime.InteropServices.InAttribute,并将 System.Runtime.InteropServices.OutAttribute 替换为‘out’修饰符。 + + + 标有 ReadOnlyArray 或 WriteOnlyArray 的非数组参数 + + + 方法‘{0}’具有不为数组的参数‘{1},并且其具有 ReadOnlyArray 特性或 WriteOnlyArray 特性。 + + + Windows 运行时不支持使用 ReadOnlyArray 或 WriteOnlyArray 标记非数组参数。 + + + 继承的接口无效 + + + Windows 运行时组件类型{0}无法实现接口{1},因为该接口不是有效的Windows 运行时接口 + + + 未定义公共类型 + + + Windows 运行时组件必须至少有一个公共类型 + + + 运算符重载已公开 + + + {0} 运算符重载,托管类型无法在 Windows 运行时中公开运算符重载 + + + 参数命名值规则 + + + 方法{0}中{1}的参数名称与生成的 C#/WinRT 互操作中使用的返回值参数名称相同;使用其他参数名称 + + + 属性必须具有公共 getter + + + 属性'{0}'没有公共 getter 方法。Windows 运行时不支持仅 setter 属性。 + {0} will be some user-defined keyword + + + 通过引用传递的参数 + + + 方法‘{0}’具有标记为‘ref’的参数‘{1}’; Windows 运行时中不允许使用引用参数 + + + 结构中的常量字段 + + + 结构{0}具有常量字段 - 常量只能出现在Windows 运行时枚举上。 + + + 结构中的字段无效 + + + 结构{0}具有{1}类型的字段;{1}不是有效的Windows 运行时字段类型。 + + + Windows 运行时结构中的每个字段只能是 UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、Single、Double、Boolean、String、Enum 或其自身的结构。 + + + 结构中的专用字段 + + + 结构 {0} 具有非公共字段。对于 Windows 运行时结构,所有字段都必须为公共字段。 + + + 空结构规则 + + + 结构{0}不包含公共字段。Windows 运行时结构必须至少包含一个公共字段。 + + + 类错误地实现接口 + + + 类‘{0}’未正确实现接口‘{1}’,因为缺少成员‘{2}’或非公开 + + + 类以解封 + + + CsWinRT 中不支持导出未密封的类型,请将类型{0}标记为密封 + {0} will be some user-defined keyword + + + 公开不受支持的类型 + + + 成员‘{0}’在其签名中具有类型‘{1}’。 + {0} and {1} will be user-defined keywords + + + 类型'{1}'不是有效的Windows 运行时类型。 + {1} will be some user-defined keyword + + + 但是,类型 (或其泛型参数) 实现的接口是有效的 Windows 运行时类型。 + + + 请考虑将成员签名中的类型‘{1} 更改为 System.Collections.Generic 中的以下类型之一: {2}。 + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/ResX/zh-TW/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-TW/CsWinRTDiagnosticStrings.resx similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/ResX/zh-TW/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-TW/CsWinRTDiagnosticStrings.resx index f19607b03..c593122d9 100644 --- a/src/Authoring/WinRT.SourceGenerator/ResX/zh-TW/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-TW/CsWinRTDiagnosticStrings.resx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 陣列參數標示為 InAttribute 或 OutAttribute - - - 方法 [{0}] 具有參數 [{1}],它是陣列,而且具有 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute。 - - - 在Windows 執行階段中,陣列參數必須有 ReadOnlyArray 或 WriteOnlyArray。 - - - 請移除這些屬性,或視需要以適當的 Windows 執行階段屬性加以取代。 - - - 陣列參數已標示為 [out] 和 ReadOnlyArray - - - 方法 [{0}] 具有輸出參數 [{1}] 這是陣列,但具有 ReadOnlyArray 屬性。 - - - 在Windows 執行階段中,輸出陣列的內容是可寫入的。請從'{1}'移除屬性。 - - - 陣列參數同時標示為 ReadOnlyArray 和 WriteOnlyArray - - - 方法 [{0}] 具有參數 [{1}],它是一個陣列,而且同時具有 ReadOnlyArray 和 WriteOnlyArray。 - - - 在Windows 執行階段中,內容陣列參數必須是可讀取或可寫入,請從'{1}'移除其中一個屬性。 - - - 陣列參數未標示為 ReadOnlyArray 或 WriteOnlyArray 方式 - - - 方法'{0}'具有參數'{1}'為數組。 - - - 在Windows 執行階段中,陣列參數的內容必須是可讀取或可寫入;請將 ReadOnlyArray 或 WriteOnlyArray 套用至 '{1}'。 - - - 類別建構函式規則 - - - 類別在 Windows 執行階段中不能有多個相同 arity 的建構函式,類別 {0} 具有多個 {1} arity 建構函式 - - - 命名空間與主要 (winmd) 命名空間不相符 - - - 公用類型具有命名空間 ('{1}')與其他命名空間 ('{0}')沒有共同首碼。 - {1} and {0} will be some user-defined keyword - - - Windows 中繼資料檔案內的所有類型都必須存在於檔案名所隱含的命名空間子命名空間中。 - "sub namespace" means a namespace defined within another namespace - - - 類別 (或介面) 為一般 - - - 類型 {0} 為一般,Windows 執行階段類型不可以是一般 - {0} will be some user-defined keyword - - - 找到有鋸齒狀陣列的陣列簽章,這不是有效的 WinRT 類型 - - - 方法 {0} 的簽章中有類型為 {1} 的巢狀陣列;Windows 執行階段方法簽章中的陣列無法為巢狀 - - - 使用多重維度陣列找到陣列簽章,這不是有效的 Windows 執行時間類型 - - - 方法 [{0}] 的簽章中有類型為 [{1}] 的多維陣列;Windows 執行階段方法簽章中的陣列必須是一維 - - - 只應指定一個超載預設值 - - - 在類別 {2}: 使用 Windows.Foundation.Metadata.DefaultOverloadAttribute 裝飾多個 {1} 的 {0}-參數超載。 - - - 屬性只能套用至方法的一個超載。 - - - 命名空間名稱不能只因大小寫而不同 - - - 找到多個名稱為 '{0}';命名空間名稱不能只因Windows 執行階段中的大小寫不同 - {0} will be some user-defined keyword - - - 已查看多個超載,但未顯示 DefaultOverload 屬性 - - - 類別{2}: {1} 的 {0}-參數超載必須使用 Windows.Foundation.Metadata.DefaultOverloadAttribute 裝飾,將它指定為預設超載的方法 - - - 參數(標示為 InAttribute 或 OutAttribute)陣列類型 - - - 方法 [{0}] 具有具有 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute.Windows 執行階段的 [{1}] 參數 Windows 執行階段不支援標記具有 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute 的參數。 - - - 請考慮移除 System.Runtime.InteropServices.InAttribute,並改用 'out' 修飾詞取代 System.Runtime.InteropServices.OutAttribute。 - - - 以 ReadOnlyArray 或 WriteOnlyArray 標示的非陣列參數 - - - 方法 [{0}] 具有非陣列的參數 [{1}],而且該參數具有 ReadOnlyArray 屬性或 WriteOnlyArray 屬性。 - - - Windows 執行階段不支援以 ReadOnlyArray 或 WriteOnlyArray 標示非陣列參數。 - - - 繼承的介面無效 - - - Windows 執行階段元件類型{0}無法實作介面{1},因為介面不是有效的Windows 執行階段介面 - - - 未定義公用類型 - - - Windows 執行階段元件必須至少有一個公用類型 - - - 運算子超載已公開 - - - {0} 為運算子超載,受管理類型無法在Windows 執行階段中公開運算子超載 - - - 參數命名值規則 - - - 方法 {0} 中{1}的參數名稱,與產生 C#/WinRT interop 中使用的傳回值參數名稱相同;使用不同的參數名稱 - - - 屬性必須有公用 getter - - - 屬性'{0}'沒有公用 getter 方法。Windows 執行階段不支援 setter 專用屬性。 - {0} will be some user-defined keyword - - - 參考所傳遞的參數 - - - 方法 [{0}] 具有參數 [{1}] 標示為 `ref';Windows 執行階段中不允許參照參數 - - - 結構中的 Const 欄位 - - - 結構 {0} 具有常數位段 - 常數只能出現在Windows 執行階段列舉上。 - - - 結構中的欄位無效 - - - 結構{0}具有類型為 {1};{1}不是有效的Windows 執行階段欄位類型。 - - - 在 Windows 執行階段結構中的每個欄位只能是 UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、Single、Double、Boolean、String、Enum 或本身的結構。 - - - 結構中的私用欄位 - - - 結構 {0} 具有非公用欄位。Windows 執行時間結構的所有欄位都必須為公用。 - - - 空白結構規則 - - - 結構{0}未包含公用欄位。Windows 執行階段結構至少必須包含一個公用欄位。 - - - 類別不正確地實作介面 - - - 類別'{0}'未正確實作介面'{1}',因為成員'{2}'遺失或非公用 - - - 類別未密封 - - - CsWinRT 不支援匯出未密封的類型,請將類型 {0} 標示為密封 - {0} will be some user-defined keyword - - - 正在公開不支援的類型 - - - 成員'{0}'的簽章中有類型'{1}'。 - {0} and {1} will be user-defined keywords - - - 類型 '{1}' 不是有效的Windows 執行階段類型。 - {1} will be some user-defined keyword - - - 不過,此類型 (或它的一般參數) 會執行有效的 Windows 執行時間類型的介面。 - - - 請考慮將成員簽章中的類型 ‘{1} 從 System.Collections.Generic 變更為下列其中一種類型: {2}。 - {1} and {2} will be keywords (types) from DotNet - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 陣列參數標示為 InAttribute 或 OutAttribute + + + 方法 [{0}] 具有參數 [{1}],它是陣列,而且具有 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute。 + + + 在Windows 執行階段中,陣列參數必須有 ReadOnlyArray 或 WriteOnlyArray。 + + + 請移除這些屬性,或視需要以適當的 Windows 執行階段屬性加以取代。 + + + 陣列參數已標示為 [out] 和 ReadOnlyArray + + + 方法 [{0}] 具有輸出參數 [{1}] 這是陣列,但具有 ReadOnlyArray 屬性。 + + + 在Windows 執行階段中,輸出陣列的內容是可寫入的。請從'{1}'移除屬性。 + + + 陣列參數同時標示為 ReadOnlyArray 和 WriteOnlyArray + + + 方法 [{0}] 具有參數 [{1}],它是一個陣列,而且同時具有 ReadOnlyArray 和 WriteOnlyArray。 + + + 在Windows 執行階段中,內容陣列參數必須是可讀取或可寫入,請從'{1}'移除其中一個屬性。 + + + 陣列參數未標示為 ReadOnlyArray 或 WriteOnlyArray 方式 + + + 方法'{0}'具有參數'{1}'為數組。 + + + 在Windows 執行階段中,陣列參數的內容必須是可讀取或可寫入;請將 ReadOnlyArray 或 WriteOnlyArray 套用至 '{1}'。 + + + 類別建構函式規則 + + + 類別在 Windows 執行階段中不能有多個相同 arity 的建構函式,類別 {0} 具有多個 {1} arity 建構函式 + + + 命名空間與主要 (winmd) 命名空間不相符 + + + 公用類型具有命名空間 ('{1}')與其他命名空間 ('{0}')沒有共同首碼。 + {1} and {0} will be some user-defined keyword + + + Windows 中繼資料檔案內的所有類型都必須存在於檔案名所隱含的命名空間子命名空間中。 + "sub namespace" means a namespace defined within another namespace + + + 類別 (或介面) 為一般 + + + 類型 {0} 為一般,Windows 執行階段類型不可以是一般 + {0} will be some user-defined keyword + + + 找到有鋸齒狀陣列的陣列簽章,這不是有效的 WinRT 類型 + + + 方法 {0} 的簽章中有類型為 {1} 的巢狀陣列;Windows 執行階段方法簽章中的陣列無法為巢狀 + + + 使用多重維度陣列找到陣列簽章,這不是有效的 Windows 執行時間類型 + + + 方法 [{0}] 的簽章中有類型為 [{1}] 的多維陣列;Windows 執行階段方法簽章中的陣列必須是一維 + + + 只應指定一個超載預設值 + + + 在類別 {2}: 使用 Windows.Foundation.Metadata.DefaultOverloadAttribute 裝飾多個 {1} 的 {0}-參數超載。 + + + 屬性只能套用至方法的一個超載。 + + + 命名空間名稱不能只因大小寫而不同 + + + 找到多個名稱為 '{0}';命名空間名稱不能只因Windows 執行階段中的大小寫不同 + {0} will be some user-defined keyword + + + 已查看多個超載,但未顯示 DefaultOverload 屬性 + + + 類別{2}: {1} 的 {0}-參數超載必須使用 Windows.Foundation.Metadata.DefaultOverloadAttribute 裝飾,將它指定為預設超載的方法 + + + 參數(標示為 InAttribute 或 OutAttribute)陣列類型 + + + 方法 [{0}] 具有具有 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute.Windows 執行階段的 [{1}] 參數 Windows 執行階段不支援標記具有 System.Runtime.InteropServices.InAttribute 或 System.Runtime.InteropServices.OutAttribute 的參數。 + + + 請考慮移除 System.Runtime.InteropServices.InAttribute,並改用 'out' 修飾詞取代 System.Runtime.InteropServices.OutAttribute。 + + + 以 ReadOnlyArray 或 WriteOnlyArray 標示的非陣列參數 + + + 方法 [{0}] 具有非陣列的參數 [{1}],而且該參數具有 ReadOnlyArray 屬性或 WriteOnlyArray 屬性。 + + + Windows 執行階段不支援以 ReadOnlyArray 或 WriteOnlyArray 標示非陣列參數。 + + + 繼承的介面無效 + + + Windows 執行階段元件類型{0}無法實作介面{1},因為介面不是有效的Windows 執行階段介面 + + + 未定義公用類型 + + + Windows 執行階段元件必須至少有一個公用類型 + + + 運算子超載已公開 + + + {0} 為運算子超載,受管理類型無法在Windows 執行階段中公開運算子超載 + + + 參數命名值規則 + + + 方法 {0} 中{1}的參數名稱,與產生 C#/WinRT interop 中使用的傳回值參數名稱相同;使用不同的參數名稱 + + + 屬性必須有公用 getter + + + 屬性'{0}'沒有公用 getter 方法。Windows 執行階段不支援 setter 專用屬性。 + {0} will be some user-defined keyword + + + 參考所傳遞的參數 + + + 方法 [{0}] 具有參數 [{1}] 標示為 `ref';Windows 執行階段中不允許參照參數 + + + 結構中的 Const 欄位 + + + 結構 {0} 具有常數位段 - 常數只能出現在Windows 執行階段列舉上。 + + + 結構中的欄位無效 + + + 結構{0}具有類型為 {1};{1}不是有效的Windows 執行階段欄位類型。 + + + 在 Windows 執行階段結構中的每個欄位只能是 UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、Single、Double、Boolean、String、Enum 或本身的結構。 + + + 結構中的私用欄位 + + + 結構 {0} 具有非公用欄位。Windows 執行時間結構的所有欄位都必須為公用。 + + + 空白結構規則 + + + 結構{0}未包含公用欄位。Windows 執行階段結構至少必須包含一個公用欄位。 + + + 類別不正確地實作介面 + + + 類別'{0}'未正確實作介面'{1}',因為成員'{2}'遺失或非公用 + + + 類別未密封 + + + CsWinRT 不支援匯出未密封的類型,請將類型 {0} 標示為密封 + {0} will be some user-defined keyword + + + 正在公開不支援的類型 + + + 成員'{0}'的簽章中有類型'{1}'。 + {0} and {1} will be user-defined keywords + + + 類型 '{1}' 不是有效的Windows 執行階段類型。 + {1} will be some user-defined keyword + + + 不過,此類型 (或它的一般參數) 會執行有效的 Windows 執行時間類型的介面。 + + + 請考慮將成員簽章中的類型 ‘{1} 從 System.Collections.Generic 變更為下列其中一種類型: {2}。 + {1} and {2} will be keywords (types) from DotNet + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/TypeMapper.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/TypeMapper.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/TypeMapper.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/TypeMapper.cs diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTAotCodeFixer.cs similarity index 98% rename from src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTAotCodeFixer.cs index eab785975..29851cec1 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTAotCodeFixer.cs @@ -1,543 +1,543 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Generator; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Composition; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace WinRT.SourceGenerator -{ - [DiagnosticAnalyzer(LanguageNames.CSharp), Shared] - public sealed class WinRTAotDiagnosticAnalyzer : DiagnosticAnalyzer - { - private static ImmutableArray _supportedDiagnostics = - ImmutableArray.Create( - WinRTRules.ClassNotAotCompatibleWarning, - WinRTRules.ClassNotAotCompatibleInfo, - WinRTRules.ClassNotAotCompatibleOldProjectionWarning, - WinRTRules.ClassNotAotCompatibleOldProjectionInfo, - WinRTRules.ClassEnableUnsafeWarning, - WinRTRules.ClassEnableUnsafeInfo, - WinRTRules.ClassWithBindableCustomPropertyNotPartial); - - public override ImmutableArray SupportedDiagnostics => _supportedDiagnostics; - - public override void Initialize(AnalysisContext context) - { - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); - context.EnableConcurrentExecution(); - - context.RegisterCompilationStartAction(static context => - { - if (!context.Options.AnalyzerConfigOptionsProvider.IsCsWinRTAotOptimizerEnabled()) - { - return; - } - - bool isComponentProject = context.Options.AnalyzerConfigOptionsProvider.IsCsWinRTComponent(); - var winrtTypeAttribute = context.Compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute"); - var winrtExposedTypeAttribute = context.Compilation.GetTypeByMetadataName("WinRT.WinRTExposedTypeAttribute"); - var generatedBindableCustomPropertyAttribute = context.Compilation.GetTypeByMetadataName("WinRT.GeneratedBindableCustomPropertyAttribute"); - if (winrtTypeAttribute is null || winrtExposedTypeAttribute is null || generatedBindableCustomPropertyAttribute is null) - { - return; - } - - bool isCsWinRTAotOptimizerAutoMode = GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation); - var generatedWinRTExposedTypeAttribute = context.Compilation.GetTypeByMetadataName("WinRT.GeneratedWinRTExposedTypeAttribute"); - var generatedWinRTExposedExternalTypeAttribute = context.Compilation.GetTypeByMetadataName("WinRT.GeneratedWinRTExposedExternalTypeAttribute"); - if (!isCsWinRTAotOptimizerAutoMode && (generatedWinRTExposedTypeAttribute is null || generatedWinRTExposedExternalTypeAttribute is null)) - { - return; - } - - var typeMapper = new TypeMapper(context.Options.AnalyzerConfigOptionsProvider.GetCsWinRTUseWindowsUIXamlProjections()); - var csWinRTAotWarningLevel = context.Options.AnalyzerConfigOptionsProvider.GetCsWinRTAotWarningLevel(); - var allowUnsafe = GeneratorHelper.AllowUnsafe(context.Compilation); - var isCsWinRTCcwLookupTableGeneratorEnabled = context.Options.AnalyzerConfigOptionsProvider.IsCsWinRTCcwLookupTableGeneratorEnabled(); - - context.RegisterSymbolAction(context => - { - // Filter to classes that can be passed as objects. - if (context.Symbol is INamedTypeSymbol namedType && - namedType.TypeKind == TypeKind.Class && - !namedType.IsAbstract && - !namedType.IsStatic) - { - // Make sure classes with the GeneratedBindableCustomProperty attribute are marked partial. - if (GeneratorHelper.HasAttributeWithType(namedType, generatedBindableCustomPropertyAttribute) && - !GeneratorHelper.IsPartial(namedType)) - { - context.ReportDiagnostic(Diagnostic.Create(WinRTRules.ClassWithBindableCustomPropertyNotPartial, namedType.Locations[0], namedType.Name)); - } - - // In opt-in mode, make sure it has the attribute asking to generate the vtable for it. - if (!isCsWinRTAotOptimizerAutoMode && !GeneratorHelper.HasAttributeWithType(namedType, generatedWinRTExposedTypeAttribute)) - { - return; - } - - // Make sure this is a class that we would generate the WinRTExposedType attribute on - // and that it isn't already partial. - if (!GeneratorHelper.IsWinRTType(namedType, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly) && - !GeneratorHelper.HasNonInstantiatedWinRTGeneric(namedType, typeMapper) && - !GeneratorHelper.HasAttributeWithType(namedType, winrtExposedTypeAttribute)) - { - var interfacesFromOldProjections = new HashSet(); - bool implementsWinRTInterfaces = false; - bool implementsCustomMappedInterfaces = false; - bool implementsGenericInterfaces = false; - foreach (var iface in namedType.AllInterfaces) - { - if (GeneratorHelper.IsWinRTType(iface, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) - { - if (!iface.IsGenericType && - GeneratorHelper.IsOldProjectionAssembly(iface.ContainingAssembly)) - { - interfacesFromOldProjections.Add(iface.Name); - } - - bool isCustomMappedType = GeneratorHelper.IsCustomMappedType(iface, typeMapper); - implementsCustomMappedInterfaces |= isCustomMappedType; - implementsWinRTInterfaces |= !isCustomMappedType; - implementsGenericInterfaces |= iface.IsGenericType; - } - } - - if (!GeneratorHelper.IsPartial(namedType) && - (implementsWinRTInterfaces || implementsCustomMappedInterfaces)) - { - // Based on the warning level, emit as a warning or as an info. - var diagnosticDescriptor = (csWinRTAotWarningLevel == 2 || (csWinRTAotWarningLevel == 1 && implementsWinRTInterfaces)) ? - WinRTRules.ClassNotAotCompatibleWarning : WinRTRules.ClassNotAotCompatibleInfo; - context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, namedType.Locations[0], namedType.Name)); - } - - if (!allowUnsafe && implementsGenericInterfaces) - { - // Based on the warning level, emit as a warning or as an info. - var diagnosticDescriptor = (csWinRTAotWarningLevel == 2 || (csWinRTAotWarningLevel == 1 && implementsWinRTInterfaces)) ? - WinRTRules.ClassEnableUnsafeWarning : WinRTRules.ClassEnableUnsafeInfo; - context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, namedType.Locations[0], namedType.Name)); - } - - if (interfacesFromOldProjections.Count > 0) - { - var diagnosticDescriptor = csWinRTAotWarningLevel >= 1 ? - WinRTRules.ClassNotAotCompatibleOldProjectionWarning : WinRTRules.ClassNotAotCompatibleOldProjectionInfo; - context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, namedType.Locations[0], namedType.Name, string.Join(", ", interfacesFromOldProjections))); - } - } - } - }, SymbolKind.NamedType); - - if (!allowUnsafe && isCsWinRTCcwLookupTableGeneratorEnabled && isCsWinRTAotOptimizerAutoMode) - { - context.RegisterSyntaxNodeAction(context => - { - var isWinRTType = GeneratorHelper.IsWinRTType(context.SemanticModel.Compilation, isComponentProject); - var isWinRTClassOrInterface = GeneratorHelper.IsWinRTClassOrInterface(context.SemanticModel.Compilation, isWinRTType, typeMapper); - - if (context.Node is InvocationExpressionSyntax invocation) - { - var invocationSymbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol; - if (invocationSymbol is IMethodSymbol methodSymbol) - { - var taskAdapter = GeneratorHelper.GetTaskAdapterIfAsyncMethod(methodSymbol); - if (!string.IsNullOrEmpty(taskAdapter)) - { - ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, methodSymbol, invocation.GetLocation(), true); - return; - } - // Filter checks for boxing and casts to ones calling CsWinRT projected functions and - // functions within same assembly. Functions within same assembly can take a boxed value - // and end up calling a projection function (i.e. ones generated by XAML compiler) - // In theory, another library can also be called which can call a projected function - // but not handling those scenarios for now. - else if(isWinRTClassOrInterface(methodSymbol.ContainingSymbol, true) || - SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly)) - { - // Get the concrete types directly from the argument rather than - // using what the method accepts, which might just be an interface, so - // that we can try to include any other WinRT interfaces implemented by - // that type on the CCW when it is marshaled. - for (int idx = 0, paramsIdx = 0; idx < invocation.ArgumentList.Arguments.Count; idx++) - { - if (methodSymbol.Parameters[paramsIdx].RefKind != RefKind.Out) - { - var argumentType = context.SemanticModel.GetTypeInfo(invocation.ArgumentList.Arguments[idx].Expression); - if (IsTypeOnLookupTable(argumentType, methodSymbol.Parameters[paramsIdx].Type, out var implementsOnlyCustomMappedInterface)) - { - ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, argumentType.Type, invocation.GetLocation(), !implementsOnlyCustomMappedInterface); - return; - } - } - - // The method parameter can be declared as params which means - // an array of arguments can be passed for it and it is the - // last argument. - if (!methodSymbol.Parameters[paramsIdx].IsParams) - { - paramsIdx++; - } - } - } - } - } - else if (context.Node is AssignmentExpressionSyntax assignment) - { - var leftSymbol = context.SemanticModel.GetSymbolInfo(assignment.Left).Symbol; - if (leftSymbol is IPropertySymbol propertySymbol && - (isWinRTClassOrInterface(propertySymbol.ContainingSymbol, true) || - SymbolEqualityComparer.Default.Equals(propertySymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) - { - var assignmentType = context.SemanticModel.GetTypeInfo(assignment.Right); - if (IsTypeOnLookupTable(assignmentType, propertySymbol.Type, out var implementsOnlyCustomMappedInterface)) - { - ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, assignmentType.Type, assignment.GetLocation(), !implementsOnlyCustomMappedInterface); - return; - } - } - else if (leftSymbol is IFieldSymbol fieldSymbol && - // WinRT interfaces don't have fields, so we don't need to check for them. - (isWinRTClassOrInterface(fieldSymbol.ContainingSymbol, false) || - SymbolEqualityComparer.Default.Equals(fieldSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) - { - var assignmentType = context.SemanticModel.GetTypeInfo(assignment.Right); - if (IsTypeOnLookupTable(assignmentType, fieldSymbol.Type, out var implementsOnlyCustomMappedInterface)) - { - ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, assignmentType.Type, assignment.GetLocation(), !implementsOnlyCustomMappedInterface); - return; - } - } - } - // Detect scenarios where the variable declaration is to a boxed or cast type during initialization. - else if (context.Node is VariableDeclarationSyntax variableDeclaration) - { - var leftSymbol = context.SemanticModel.GetSymbolInfo(variableDeclaration.Type).Symbol; - if (leftSymbol is INamedTypeSymbol namedType) - { - foreach (var variable in variableDeclaration.Variables) - { - if (variable.Initializer != null) - { - var instantiatedType = context.SemanticModel.GetTypeInfo(variable.Initializer.Value); - if (IsTypeOnLookupTable(instantiatedType, namedType, out var implementsOnlyCustomMappedInterface)) - { - ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, instantiatedType.Type, variableDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); - return; - } - } - } - } - } - // Detect scenarios where the property declaration has an initializer and is to a boxed or cast type during initialization. - else if (context.Node is PropertyDeclarationSyntax propertyDeclaration) - { - if (propertyDeclaration.Initializer != null) - { - var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol; - if (leftSymbol is INamedTypeSymbol namedType) - { - var instantiatedType = context.SemanticModel.GetTypeInfo(propertyDeclaration.Initializer.Value); - if (IsTypeOnLookupTable(instantiatedType, namedType, out var implementsOnlyCustomMappedInterface)) - { - ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, instantiatedType.Type, propertyDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); - return; - } - } - } - else if (propertyDeclaration.ExpressionBody != null) - { - var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol; - if (leftSymbol is INamedTypeSymbol namedType) - { - var instantiatedType = context.SemanticModel.GetTypeInfo(propertyDeclaration.ExpressionBody.Expression); - if (IsTypeOnLookupTable(instantiatedType, namedType, out var implementsOnlyCustomMappedInterface)) - { - ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, instantiatedType.Type, propertyDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); - return; - } - } - } - } - // Detect scenarios where the method or property being returned from is doing a box or cast of the type - // in the return statement. - else if (context.Node is ReturnStatementSyntax returnDeclaration && returnDeclaration.Expression is not null) - { - var returnSymbol = context.SemanticModel.GetTypeInfo(returnDeclaration.Expression); - var parent = returnDeclaration.Ancestors().OfType().FirstOrDefault(); - if (parent is MethodDeclarationSyntax methodDeclaration) - { - var methodReturnSymbol = context.SemanticModel.GetSymbolInfo(methodDeclaration.ReturnType).Symbol; - if (methodReturnSymbol is ITypeSymbol typeSymbol) - { - if (IsTypeOnLookupTable(returnSymbol, typeSymbol, out var implementsOnlyCustomMappedInterface)) - { - ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, returnSymbol.Type, returnDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); - return; - } - } - } - else if (parent is BasePropertyDeclarationSyntax propertyDeclarationSyntax) - { - var propertyTypeSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclarationSyntax.Type).Symbol; - if (propertyTypeSymbol is ITypeSymbol typeSymbol) - { - if (IsTypeOnLookupTable(returnSymbol, typeSymbol, out var implementsOnlyCustomMappedInterface)) - { - ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, returnSymbol.Type, returnDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); - return; - } - } - } - } - - bool IsTypeOnLookupTable(Microsoft.CodeAnalysis.TypeInfo instantiatedType, ITypeSymbol convertedToTypeSymbol, out bool implementsOnlyCustomMappedInterface) - { - if (instantiatedType.Type is IArrayTypeSymbol arrayType) - { - if (convertedToTypeSymbol is not IArrayTypeSymbol && - // Make sure we aren't just assigning it to a value type such as ReadOnlySpan - !convertedToTypeSymbol.IsValueType && - GeneratorHelper.IsWinRTTypeOrImplementsWinRTType(arrayType.ElementType, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) - { - // Arrays are projected as a list which is a custom mapped type, but if the element type is an actual WinRT type, - // then we don't consider it as implemented only custom mapped interfaces. - implementsOnlyCustomMappedInterface = GeneratorHelper.IsCustomMappedType(arrayType.ElementType, typeMapper); - return true; - } - } - else if (instantiatedType.Type is not null || instantiatedType.ConvertedType is not null) - { - // Type might be null such as for lambdas, so check converted type in that case. - var instantiatedTypeSymbol = instantiatedType.Type ?? instantiatedType.ConvertedType; - - // This handles the case where a generic delegate is passed to a parameter - // statically declared as an object and thereby we won't be able to detect - // its actual type and handle it at compile time within the generated projection. - // When it is not declared as an object parameter but rather the generic delegate - // type itself, the generated marshaler code in the function makes sure the vtable - // information is available. - if (instantiatedTypeSymbol.TypeKind == TypeKind.Delegate && - instantiatedTypeSymbol.MetadataName.Contains("`") && - GeneratorHelper.IsWinRTType(instantiatedTypeSymbol, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly) && - convertedToTypeSymbol.SpecialType == SpecialType.System_Object) - { - implementsOnlyCustomMappedInterface = GeneratorHelper.IsCustomMappedType(instantiatedTypeSymbol, typeMapper); - return true; - } - - // This handles the case where the source generator wasn't able to run - // and put the WinRTExposedType attribute on the class. This can be in the - // scenario where the caller defined their own generic class and - // pass it as a parameter. With generic classes, the interface itself - // might be generic too and due to that we handle it here. - // This also handles the case where the type being passed is from a different - // library which happened to not run the AOT optimizer. So as a best effort, - // we handle it here. - if (instantiatedTypeSymbol.TypeKind == TypeKind.Class) - { - bool addClassOnLookupTable = false; - if (instantiatedTypeSymbol.MetadataName.Contains("`")) - { - addClassOnLookupTable = - !GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) && - // If the type is defined in the same assembly as what the source generator is running on, - // we let the WinRTExposedType attribute generator handle it. The only scenario the generator - // doesn't handle which we handle here is if it is a generic type implementing generic WinRT interfaces. - (!SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) || - GeneratorHelper.HasNonInstantiatedWinRTGeneric(instantiatedTypeSymbol.OriginalDefinition, typeMapper)) && - // Make sure the type we are passing is being boxed or cast to another interface. - !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol); - } - else if (!GeneratorHelper.IsWinRTType(instantiatedTypeSymbol, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) - { - addClassOnLookupTable = - !GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) && - // If the type is defined in the same assembly as what the source generator is running on, - // we let the WinRTExposedType attribute generator handle it. - !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) && - // Make sure the type we are passing is being boxed or cast to another interface. - !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol); - } - - if (addClassOnLookupTable) - { - // We loop through all the interfaces rather than stopping at the first WinRT interface - // to determine whether it is also custom mapped WinRT interfaces or not. - implementsOnlyCustomMappedInterface = true; - bool implementsWinRTInterface = false; - foreach (var iface in instantiatedTypeSymbol.AllInterfaces) - { - if (GeneratorHelper.IsWinRTType(iface, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) - { - implementsWinRTInterface = true; - implementsOnlyCustomMappedInterface &= GeneratorHelper.IsCustomMappedType(iface, typeMapper); - } - } - return implementsWinRTInterface; - } - } - } - - implementsOnlyCustomMappedInterface = false; - return false; - } - }, SyntaxKind.InvocationExpression, SyntaxKind.VariableDeclaration, SyntaxKind.PropertyDeclaration, SyntaxKind.ReturnStatement, SyntaxKind.SimpleAssignmentExpression); - - void ReportEnableUnsafeDiagnostic(Action reportDiagnostic, ISymbol symbol, Location location, bool implementsWinRTInterfaces) - { - // Based on the warning level, emit as a warning or as an info. - var diagnosticDescriptor = (csWinRTAotWarningLevel == 2 || (csWinRTAotWarningLevel == 1 && implementsWinRTInterfaces)) ? - WinRTRules.ClassEnableUnsafeWarning : WinRTRules.ClassEnableUnsafeInfo; - reportDiagnostic(Diagnostic.Create(diagnosticDescriptor, location, symbol)); - } - } - - if (!allowUnsafe && isCsWinRTCcwLookupTableGeneratorEnabled && !isCsWinRTAotOptimizerAutoMode) - { - context.RegisterCompilationEndAction(context => - { - // If any of generated code for the type in the attribute requires unsafe code, report the first one. - foreach (AttributeData attributeData in context.Compilation.Assembly.GetAttributes()) - { - if (SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, generatedWinRTExposedExternalTypeAttribute)) - { - if (attributeData.ConstructorArguments is [{ Kind: TypedConstantKind.Type, Value: ITypeSymbol vtableType }]) - { - if (vtableType is IArrayTypeSymbol) - { - context.ReportDiagnostic(Diagnostic.Create(WinRTRules.ClassEnableUnsafeWarning, null, vtableType)); - return; - } - else if (vtableType.TypeKind == TypeKind.Delegate && - vtableType.MetadataName.Contains("`") && - GeneratorHelper.IsWinRTType(vtableType, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) - { - context.ReportDiagnostic(Diagnostic.Create(WinRTRules.ClassEnableUnsafeWarning, null, vtableType)); - return; - } - else if (vtableType.TypeKind == TypeKind.Class) - { - foreach (var iface in vtableType.AllInterfaces) - { - if (iface.IsGenericType && - (GeneratorHelper.IsWinRTType(iface, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly) || - GeneratorHelper.IsWinRTType(iface.OriginalDefinition, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly))) - { - context.ReportDiagnostic(Diagnostic.Create(WinRTRules.ClassEnableUnsafeWarning, null, vtableType)); - return; - } - } - } - } - } - } - }); - } - }); - } - } - - [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(WinRTAotCodeFixer)), Shared] - public sealed class WinRTAotCodeFixer : CodeFixProvider - { - private const string title = "Make type partial"; - - private static ImmutableArray _fixableDiagnosticIds = ImmutableArray.Create(WinRTRules.ClassNotAotCompatibleWarning.Id); - - public override ImmutableArray FixableDiagnosticIds => _fixableDiagnosticIds; - - public override async Task RegisterCodeFixesAsync(CodeFixContext context) - { - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - if (root is null) - return; - - var node = root.FindNode(context.Span); - if (node is null) - return; - - var declaration = node.FirstAncestorOrSelf(); - if (declaration is null) - return; - - context.RegisterCodeFix( - CodeAction.Create( - title, - ct => MakeTypePartial(context.Document, declaration, ct), - nameof(WinRTAotCodeFixer)), - context.Diagnostics); - } - - private static async Task MakeTypePartial(Document document, ClassDeclarationSyntax @class, CancellationToken token) - { - var oldRoot = await document.GetSyntaxRootAsync(token).ConfigureAwait(false); - if (oldRoot is null) - return document; - - var newRoot = oldRoot.ReplaceNodes(@class.AncestorsAndSelf().OfType(), - (_, typeDeclaration) => - { - if (!typeDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword)) - { - return typeDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword)); - } - - return typeDeclaration; - }); - - return document.WithSyntaxRoot(newRoot); - } - - public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - } - - [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(WinRTAotEnableUnsafeCodeFixer)), Shared] - public sealed class WinRTAotEnableUnsafeCodeFixer : CodeFixProvider - { - private const string title = "Update project with EnableUnsafeBlocks set to true"; - - private static ImmutableArray _fixableDiagnosticIds = ImmutableArray.Create(WinRTRules.ClassEnableUnsafeWarning.Id); - - public override ImmutableArray FixableDiagnosticIds => _fixableDiagnosticIds; - - public override Task RegisterCodeFixesAsync(CodeFixContext context) - { - return Task.Run(() => RegisterCodeFixes(context)); - } - - private static void RegisterCodeFixes(CodeFixContext context) - { - if (context.Document.Project.CompilationOptions is not CSharpCompilationOptions) - return; - - context.RegisterCodeFix( - CodeAction.Create( - title, - ct => EnableUnsafe(context.Document.Project.Solution, context.Document.Project, ct), - nameof(WinRTAotEnableUnsafeCodeFixer)), - context.Diagnostics); - } - - private static Task EnableUnsafe(Solution solution, Project project, CancellationToken token) - { - return Task.FromResult( - solution.WithProjectCompilationOptions(project.Id, ((CSharpCompilationOptions)project.CompilationOptions).WithAllowUnsafe(true))); - } - - public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - } -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Generator; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace WinRT.SourceGenerator +{ + [DiagnosticAnalyzer(LanguageNames.CSharp), Shared] + public sealed class WinRTAotDiagnosticAnalyzer : DiagnosticAnalyzer + { + private static ImmutableArray _supportedDiagnostics = + ImmutableArray.Create( + WinRTRules.ClassNotAotCompatibleWarning, + WinRTRules.ClassNotAotCompatibleInfo, + WinRTRules.ClassNotAotCompatibleOldProjectionWarning, + WinRTRules.ClassNotAotCompatibleOldProjectionInfo, + WinRTRules.ClassEnableUnsafeWarning, + WinRTRules.ClassEnableUnsafeInfo, + WinRTRules.ClassWithBindableCustomPropertyNotPartial); + + public override ImmutableArray SupportedDiagnostics => _supportedDiagnostics; + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(static context => + { + if (!context.Options.AnalyzerConfigOptionsProvider.IsCsWinRTAotOptimizerEnabled()) + { + return; + } + + bool isComponentProject = context.Options.AnalyzerConfigOptionsProvider.IsCsWinRTComponent(); + var winrtTypeAttribute = context.Compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute"); + var winrtExposedTypeAttribute = context.Compilation.GetTypeByMetadataName("WinRT.WinRTExposedTypeAttribute"); + var generatedBindableCustomPropertyAttribute = context.Compilation.GetTypeByMetadataName("WinRT.GeneratedBindableCustomPropertyAttribute"); + if (winrtTypeAttribute is null || winrtExposedTypeAttribute is null || generatedBindableCustomPropertyAttribute is null) + { + return; + } + + bool isCsWinRTAotOptimizerAutoMode = GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation); + var generatedWinRTExposedTypeAttribute = context.Compilation.GetTypeByMetadataName("WinRT.GeneratedWinRTExposedTypeAttribute"); + var generatedWinRTExposedExternalTypeAttribute = context.Compilation.GetTypeByMetadataName("WinRT.GeneratedWinRTExposedExternalTypeAttribute"); + if (!isCsWinRTAotOptimizerAutoMode && (generatedWinRTExposedTypeAttribute is null || generatedWinRTExposedExternalTypeAttribute is null)) + { + return; + } + + var typeMapper = new TypeMapper(context.Options.AnalyzerConfigOptionsProvider.GetCsWinRTUseWindowsUIXamlProjections()); + var csWinRTAotWarningLevel = context.Options.AnalyzerConfigOptionsProvider.GetCsWinRTAotWarningLevel(); + var allowUnsafe = GeneratorHelper.AllowUnsafe(context.Compilation); + var isCsWinRTCcwLookupTableGeneratorEnabled = context.Options.AnalyzerConfigOptionsProvider.IsCsWinRTCcwLookupTableGeneratorEnabled(); + + context.RegisterSymbolAction(context => + { + // Filter to classes that can be passed as objects. + if (context.Symbol is INamedTypeSymbol namedType && + namedType.TypeKind == TypeKind.Class && + !namedType.IsAbstract && + !namedType.IsStatic) + { + // Make sure classes with the GeneratedBindableCustomProperty attribute are marked partial. + if (GeneratorHelper.HasAttributeWithType(namedType, generatedBindableCustomPropertyAttribute) && + !GeneratorHelper.IsPartial(namedType)) + { + context.ReportDiagnostic(Diagnostic.Create(WinRTRules.ClassWithBindableCustomPropertyNotPartial, namedType.Locations[0], namedType.Name)); + } + + // In opt-in mode, make sure it has the attribute asking to generate the vtable for it. + if (!isCsWinRTAotOptimizerAutoMode && !GeneratorHelper.HasAttributeWithType(namedType, generatedWinRTExposedTypeAttribute)) + { + return; + } + + // Make sure this is a class that we would generate the WinRTExposedType attribute on + // and that it isn't already partial. + if (!GeneratorHelper.IsWinRTType(namedType, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly) && + !GeneratorHelper.HasNonInstantiatedWinRTGeneric(namedType, typeMapper) && + !GeneratorHelper.HasAttributeWithType(namedType, winrtExposedTypeAttribute)) + { + var interfacesFromOldProjections = new HashSet(); + bool implementsWinRTInterfaces = false; + bool implementsCustomMappedInterfaces = false; + bool implementsGenericInterfaces = false; + foreach (var iface in namedType.AllInterfaces) + { + if (GeneratorHelper.IsWinRTType(iface, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) + { + if (!iface.IsGenericType && + GeneratorHelper.IsOldProjectionAssembly(iface.ContainingAssembly)) + { + interfacesFromOldProjections.Add(iface.Name); + } + + bool isCustomMappedType = GeneratorHelper.IsCustomMappedType(iface, typeMapper); + implementsCustomMappedInterfaces |= isCustomMappedType; + implementsWinRTInterfaces |= !isCustomMappedType; + implementsGenericInterfaces |= iface.IsGenericType; + } + } + + if (!GeneratorHelper.IsPartial(namedType) && + (implementsWinRTInterfaces || implementsCustomMappedInterfaces)) + { + // Based on the warning level, emit as a warning or as an info. + var diagnosticDescriptor = (csWinRTAotWarningLevel == 2 || (csWinRTAotWarningLevel == 1 && implementsWinRTInterfaces)) ? + WinRTRules.ClassNotAotCompatibleWarning : WinRTRules.ClassNotAotCompatibleInfo; + context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, namedType.Locations[0], namedType.Name)); + } + + if (!allowUnsafe && implementsGenericInterfaces) + { + // Based on the warning level, emit as a warning or as an info. + var diagnosticDescriptor = (csWinRTAotWarningLevel == 2 || (csWinRTAotWarningLevel == 1 && implementsWinRTInterfaces)) ? + WinRTRules.ClassEnableUnsafeWarning : WinRTRules.ClassEnableUnsafeInfo; + context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, namedType.Locations[0], namedType.Name)); + } + + if (interfacesFromOldProjections.Count > 0) + { + var diagnosticDescriptor = csWinRTAotWarningLevel >= 1 ? + WinRTRules.ClassNotAotCompatibleOldProjectionWarning : WinRTRules.ClassNotAotCompatibleOldProjectionInfo; + context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, namedType.Locations[0], namedType.Name, string.Join(", ", interfacesFromOldProjections))); + } + } + } + }, SymbolKind.NamedType); + + if (!allowUnsafe && isCsWinRTCcwLookupTableGeneratorEnabled && isCsWinRTAotOptimizerAutoMode) + { + context.RegisterSyntaxNodeAction(context => + { + var isWinRTType = GeneratorHelper.IsWinRTType(context.SemanticModel.Compilation, isComponentProject); + var isWinRTClassOrInterface = GeneratorHelper.IsWinRTClassOrInterface(context.SemanticModel.Compilation, isWinRTType, typeMapper); + + if (context.Node is InvocationExpressionSyntax invocation) + { + var invocationSymbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol; + if (invocationSymbol is IMethodSymbol methodSymbol) + { + var taskAdapter = GeneratorHelper.GetTaskAdapterIfAsyncMethod(methodSymbol); + if (!string.IsNullOrEmpty(taskAdapter)) + { + ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, methodSymbol, invocation.GetLocation(), true); + return; + } + // Filter checks for boxing and casts to ones calling CsWinRT projected functions and + // functions within same assembly. Functions within same assembly can take a boxed value + // and end up calling a projection function (i.e. ones generated by XAML compiler) + // In theory, another library can also be called which can call a projected function + // but not handling those scenarios for now. + else if(isWinRTClassOrInterface(methodSymbol.ContainingSymbol, true) || + SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly)) + { + // Get the concrete types directly from the argument rather than + // using what the method accepts, which might just be an interface, so + // that we can try to include any other WinRT interfaces implemented by + // that type on the CCW when it is marshaled. + for (int idx = 0, paramsIdx = 0; idx < invocation.ArgumentList.Arguments.Count; idx++) + { + if (methodSymbol.Parameters[paramsIdx].RefKind != RefKind.Out) + { + var argumentType = context.SemanticModel.GetTypeInfo(invocation.ArgumentList.Arguments[idx].Expression); + if (IsTypeOnLookupTable(argumentType, methodSymbol.Parameters[paramsIdx].Type, out var implementsOnlyCustomMappedInterface)) + { + ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, argumentType.Type, invocation.GetLocation(), !implementsOnlyCustomMappedInterface); + return; + } + } + + // The method parameter can be declared as params which means + // an array of arguments can be passed for it and it is the + // last argument. + if (!methodSymbol.Parameters[paramsIdx].IsParams) + { + paramsIdx++; + } + } + } + } + } + else if (context.Node is AssignmentExpressionSyntax assignment) + { + var leftSymbol = context.SemanticModel.GetSymbolInfo(assignment.Left).Symbol; + if (leftSymbol is IPropertySymbol propertySymbol && + (isWinRTClassOrInterface(propertySymbol.ContainingSymbol, true) || + SymbolEqualityComparer.Default.Equals(propertySymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) + { + var assignmentType = context.SemanticModel.GetTypeInfo(assignment.Right); + if (IsTypeOnLookupTable(assignmentType, propertySymbol.Type, out var implementsOnlyCustomMappedInterface)) + { + ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, assignmentType.Type, assignment.GetLocation(), !implementsOnlyCustomMappedInterface); + return; + } + } + else if (leftSymbol is IFieldSymbol fieldSymbol && + // WinRT interfaces don't have fields, so we don't need to check for them. + (isWinRTClassOrInterface(fieldSymbol.ContainingSymbol, false) || + SymbolEqualityComparer.Default.Equals(fieldSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) + { + var assignmentType = context.SemanticModel.GetTypeInfo(assignment.Right); + if (IsTypeOnLookupTable(assignmentType, fieldSymbol.Type, out var implementsOnlyCustomMappedInterface)) + { + ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, assignmentType.Type, assignment.GetLocation(), !implementsOnlyCustomMappedInterface); + return; + } + } + } + // Detect scenarios where the variable declaration is to a boxed or cast type during initialization. + else if (context.Node is VariableDeclarationSyntax variableDeclaration) + { + var leftSymbol = context.SemanticModel.GetSymbolInfo(variableDeclaration.Type).Symbol; + if (leftSymbol is INamedTypeSymbol namedType) + { + foreach (var variable in variableDeclaration.Variables) + { + if (variable.Initializer != null) + { + var instantiatedType = context.SemanticModel.GetTypeInfo(variable.Initializer.Value); + if (IsTypeOnLookupTable(instantiatedType, namedType, out var implementsOnlyCustomMappedInterface)) + { + ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, instantiatedType.Type, variableDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); + return; + } + } + } + } + } + // Detect scenarios where the property declaration has an initializer and is to a boxed or cast type during initialization. + else if (context.Node is PropertyDeclarationSyntax propertyDeclaration) + { + if (propertyDeclaration.Initializer != null) + { + var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol; + if (leftSymbol is INamedTypeSymbol namedType) + { + var instantiatedType = context.SemanticModel.GetTypeInfo(propertyDeclaration.Initializer.Value); + if (IsTypeOnLookupTable(instantiatedType, namedType, out var implementsOnlyCustomMappedInterface)) + { + ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, instantiatedType.Type, propertyDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); + return; + } + } + } + else if (propertyDeclaration.ExpressionBody != null) + { + var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol; + if (leftSymbol is INamedTypeSymbol namedType) + { + var instantiatedType = context.SemanticModel.GetTypeInfo(propertyDeclaration.ExpressionBody.Expression); + if (IsTypeOnLookupTable(instantiatedType, namedType, out var implementsOnlyCustomMappedInterface)) + { + ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, instantiatedType.Type, propertyDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); + return; + } + } + } + } + // Detect scenarios where the method or property being returned from is doing a box or cast of the type + // in the return statement. + else if (context.Node is ReturnStatementSyntax returnDeclaration && returnDeclaration.Expression is not null) + { + var returnSymbol = context.SemanticModel.GetTypeInfo(returnDeclaration.Expression); + var parent = returnDeclaration.Ancestors().OfType().FirstOrDefault(); + if (parent is MethodDeclarationSyntax methodDeclaration) + { + var methodReturnSymbol = context.SemanticModel.GetSymbolInfo(methodDeclaration.ReturnType).Symbol; + if (methodReturnSymbol is ITypeSymbol typeSymbol) + { + if (IsTypeOnLookupTable(returnSymbol, typeSymbol, out var implementsOnlyCustomMappedInterface)) + { + ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, returnSymbol.Type, returnDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); + return; + } + } + } + else if (parent is BasePropertyDeclarationSyntax propertyDeclarationSyntax) + { + var propertyTypeSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclarationSyntax.Type).Symbol; + if (propertyTypeSymbol is ITypeSymbol typeSymbol) + { + if (IsTypeOnLookupTable(returnSymbol, typeSymbol, out var implementsOnlyCustomMappedInterface)) + { + ReportEnableUnsafeDiagnostic(context.ReportDiagnostic, returnSymbol.Type, returnDeclaration.GetLocation(), !implementsOnlyCustomMappedInterface); + return; + } + } + } + } + + bool IsTypeOnLookupTable(Microsoft.CodeAnalysis.TypeInfo instantiatedType, ITypeSymbol convertedToTypeSymbol, out bool implementsOnlyCustomMappedInterface) + { + if (instantiatedType.Type is IArrayTypeSymbol arrayType) + { + if (convertedToTypeSymbol is not IArrayTypeSymbol && + // Make sure we aren't just assigning it to a value type such as ReadOnlySpan + !convertedToTypeSymbol.IsValueType && + GeneratorHelper.IsWinRTTypeOrImplementsWinRTType(arrayType.ElementType, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) + { + // Arrays are projected as a list which is a custom mapped type, but if the element type is an actual WinRT type, + // then we don't consider it as implemented only custom mapped interfaces. + implementsOnlyCustomMappedInterface = GeneratorHelper.IsCustomMappedType(arrayType.ElementType, typeMapper); + return true; + } + } + else if (instantiatedType.Type is not null || instantiatedType.ConvertedType is not null) + { + // Type might be null such as for lambdas, so check converted type in that case. + var instantiatedTypeSymbol = instantiatedType.Type ?? instantiatedType.ConvertedType; + + // This handles the case where a generic delegate is passed to a parameter + // statically declared as an object and thereby we won't be able to detect + // its actual type and handle it at compile time within the generated projection. + // When it is not declared as an object parameter but rather the generic delegate + // type itself, the generated marshaler code in the function makes sure the vtable + // information is available. + if (instantiatedTypeSymbol.TypeKind == TypeKind.Delegate && + instantiatedTypeSymbol.MetadataName.Contains("`") && + GeneratorHelper.IsWinRTType(instantiatedTypeSymbol, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly) && + convertedToTypeSymbol.SpecialType == SpecialType.System_Object) + { + implementsOnlyCustomMappedInterface = GeneratorHelper.IsCustomMappedType(instantiatedTypeSymbol, typeMapper); + return true; + } + + // This handles the case where the source generator wasn't able to run + // and put the WinRTExposedType attribute on the class. This can be in the + // scenario where the caller defined their own generic class and + // pass it as a parameter. With generic classes, the interface itself + // might be generic too and due to that we handle it here. + // This also handles the case where the type being passed is from a different + // library which happened to not run the AOT optimizer. So as a best effort, + // we handle it here. + if (instantiatedTypeSymbol.TypeKind == TypeKind.Class) + { + bool addClassOnLookupTable = false; + if (instantiatedTypeSymbol.MetadataName.Contains("`")) + { + addClassOnLookupTable = + !GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) && + // If the type is defined in the same assembly as what the source generator is running on, + // we let the WinRTExposedType attribute generator handle it. The only scenario the generator + // doesn't handle which we handle here is if it is a generic type implementing generic WinRT interfaces. + (!SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) || + GeneratorHelper.HasNonInstantiatedWinRTGeneric(instantiatedTypeSymbol.OriginalDefinition, typeMapper)) && + // Make sure the type we are passing is being boxed or cast to another interface. + !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol); + } + else if (!GeneratorHelper.IsWinRTType(instantiatedTypeSymbol, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) + { + addClassOnLookupTable = + !GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) && + // If the type is defined in the same assembly as what the source generator is running on, + // we let the WinRTExposedType attribute generator handle it. + !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) && + // Make sure the type we are passing is being boxed or cast to another interface. + !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol); + } + + if (addClassOnLookupTable) + { + // We loop through all the interfaces rather than stopping at the first WinRT interface + // to determine whether it is also custom mapped WinRT interfaces or not. + implementsOnlyCustomMappedInterface = true; + bool implementsWinRTInterface = false; + foreach (var iface in instantiatedTypeSymbol.AllInterfaces) + { + if (GeneratorHelper.IsWinRTType(iface, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) + { + implementsWinRTInterface = true; + implementsOnlyCustomMappedInterface &= GeneratorHelper.IsCustomMappedType(iface, typeMapper); + } + } + return implementsWinRTInterface; + } + } + } + + implementsOnlyCustomMappedInterface = false; + return false; + } + }, SyntaxKind.InvocationExpression, SyntaxKind.VariableDeclaration, SyntaxKind.PropertyDeclaration, SyntaxKind.ReturnStatement, SyntaxKind.SimpleAssignmentExpression); + + void ReportEnableUnsafeDiagnostic(Action reportDiagnostic, ISymbol symbol, Location location, bool implementsWinRTInterfaces) + { + // Based on the warning level, emit as a warning or as an info. + var diagnosticDescriptor = (csWinRTAotWarningLevel == 2 || (csWinRTAotWarningLevel == 1 && implementsWinRTInterfaces)) ? + WinRTRules.ClassEnableUnsafeWarning : WinRTRules.ClassEnableUnsafeInfo; + reportDiagnostic(Diagnostic.Create(diagnosticDescriptor, location, symbol)); + } + } + + if (!allowUnsafe && isCsWinRTCcwLookupTableGeneratorEnabled && !isCsWinRTAotOptimizerAutoMode) + { + context.RegisterCompilationEndAction(context => + { + // If any of generated code for the type in the attribute requires unsafe code, report the first one. + foreach (AttributeData attributeData in context.Compilation.Assembly.GetAttributes()) + { + if (SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, generatedWinRTExposedExternalTypeAttribute)) + { + if (attributeData.ConstructorArguments is [{ Kind: TypedConstantKind.Type, Value: ITypeSymbol vtableType }]) + { + if (vtableType is IArrayTypeSymbol) + { + context.ReportDiagnostic(Diagnostic.Create(WinRTRules.ClassEnableUnsafeWarning, null, vtableType)); + return; + } + else if (vtableType.TypeKind == TypeKind.Delegate && + vtableType.MetadataName.Contains("`") && + GeneratorHelper.IsWinRTType(vtableType, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) + { + context.ReportDiagnostic(Diagnostic.Create(WinRTRules.ClassEnableUnsafeWarning, null, vtableType)); + return; + } + else if (vtableType.TypeKind == TypeKind.Class) + { + foreach (var iface in vtableType.AllInterfaces) + { + if (iface.IsGenericType && + (GeneratorHelper.IsWinRTType(iface, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly) || + GeneratorHelper.IsWinRTType(iface.OriginalDefinition, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly))) + { + context.ReportDiagnostic(Diagnostic.Create(WinRTRules.ClassEnableUnsafeWarning, null, vtableType)); + return; + } + } + } + } + } + } + }); + } + }); + } + } + + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(WinRTAotCodeFixer)), Shared] + public sealed class WinRTAotCodeFixer : CodeFixProvider + { + private const string title = "Make type partial"; + + private static ImmutableArray _fixableDiagnosticIds = ImmutableArray.Create(WinRTRules.ClassNotAotCompatibleWarning.Id); + + public override ImmutableArray FixableDiagnosticIds => _fixableDiagnosticIds; + + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root is null) + return; + + var node = root.FindNode(context.Span); + if (node is null) + return; + + var declaration = node.FirstAncestorOrSelf(); + if (declaration is null) + return; + + context.RegisterCodeFix( + CodeAction.Create( + title, + ct => MakeTypePartial(context.Document, declaration, ct), + nameof(WinRTAotCodeFixer)), + context.Diagnostics); + } + + private static async Task MakeTypePartial(Document document, ClassDeclarationSyntax @class, CancellationToken token) + { + var oldRoot = await document.GetSyntaxRootAsync(token).ConfigureAwait(false); + if (oldRoot is null) + return document; + + var newRoot = oldRoot.ReplaceNodes(@class.AncestorsAndSelf().OfType(), + (_, typeDeclaration) => + { + if (!typeDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword)) + { + return typeDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword)); + } + + return typeDeclaration; + }); + + return document.WithSyntaxRoot(newRoot); + } + + public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + } + + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(WinRTAotEnableUnsafeCodeFixer)), Shared] + public sealed class WinRTAotEnableUnsafeCodeFixer : CodeFixProvider + { + private const string title = "Update project with EnableUnsafeBlocks set to true"; + + private static ImmutableArray _fixableDiagnosticIds = ImmutableArray.Create(WinRTRules.ClassEnableUnsafeWarning.Id); + + public override ImmutableArray FixableDiagnosticIds => _fixableDiagnosticIds; + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + return Task.Run(() => RegisterCodeFixes(context)); + } + + private static void RegisterCodeFixes(CodeFixContext context) + { + if (context.Document.Project.CompilationOptions is not CSharpCompilationOptions) + return; + + context.RegisterCodeFix( + CodeAction.Create( + title, + ct => EnableUnsafe(context.Document.Project.Solution, context.Document.Project, ct), + nameof(WinRTAotEnableUnsafeCodeFixer)), + context.Diagnostics); + } + + private static Task EnableUnsafe(Solution solution, Project project, CancellationToken token) + { + return Task.FromResult( + solution.WithProjectCompilationOptions(project.Id, ((CSharpCompilationOptions)project.CompilationOptions).WithAllowUnsafe(true))); + } + + public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTRules.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/WinRTRules.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTRules.cs diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTSuppressions.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTSuppressions.cs diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTTypeWriter.cs similarity index 97% rename from src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs rename to src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTTypeWriter.cs index 56066b306..0e62ca5e6 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTTypeWriter.cs @@ -1,2860 +1,2860 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Security.Cryptography; -using System.Text; - -namespace Generator -{ - class Parameter - { - public Symbol Type; - public string Name; - public ParameterAttributes Attributes; - public bool ByRef; - - public Parameter(Symbol type, string name, ParameterAttributes attributes) - : this(type, name, attributes, attributes == ParameterAttributes.Out) - { - } - - public Parameter(Symbol type, string name, ParameterAttributes attributes, bool byRef) - { - Type = type; - Name = name; - Attributes = attributes; - ByRef = byRef; - } - - public Parameter(ITypeSymbol type, string name, ParameterAttributes attributes) - : this(new Symbol(type), name, attributes) - { - } - - public Parameter(EntityHandle type, string name, ParameterAttributes attributes) - : this(new Symbol(type), name, attributes) - { - } - - public Parameter(IParameterSymbol parameterSymbol) - { - // Set out parameter attribute if write only array. - bool isWriteOnlyArray = parameterSymbol.Type is IArrayTypeSymbol && - parameterSymbol.GetAttributes().Where( - attr => string.CompareOrdinal(attr.AttributeClass.ToString(), "System.Runtime.InteropServices.WindowsRuntime.WriteOnlyArrayAttribute") == 0 - ).Count() != 0; - - Type = new Symbol(parameterSymbol.Type); - Name = parameterSymbol.Name; - Attributes = (parameterSymbol.RefKind == RefKind.Out || isWriteOnlyArray) ? ParameterAttributes.Out : ParameterAttributes.In; - ByRef = parameterSymbol.RefKind == RefKind.Out; - } - - public static Parameter[] GetParameters(ParameterListSyntax parameterList, SemanticModel model) - { - int numParameters = parameterList.Parameters.Count; - Parameter[] parameters = new Parameter[numParameters]; - for (int idx = 0; idx < numParameters; idx++) - { - parameters[idx] = new Parameter(model.GetDeclaredSymbol(parameterList.Parameters[idx])); - } - - return parameters; - } - - public static Parameter[] GetParameters(IMethodSymbol method) - { - int numParameters = method.Parameters.Count(); - Parameter[] parameters = new Parameter[numParameters]; - for (int idx = 0; idx < numParameters; idx++) - { - parameters[idx] = new Parameter(method.Parameters[idx]); - } - - return parameters; - } - } - - class Symbol - { - public ITypeSymbol Type; - public EntityHandle Handle; - public int GenericIndex; - public bool IsArray; - - public Symbol(ITypeSymbol type, bool isArray = false) - { - Type = type; - Handle = default; - GenericIndex = -1; - IsArray = isArray; - } - - public Symbol(EntityHandle handle) - { - Type = default; - Handle = handle; - GenericIndex = -1; - } - - public Symbol(int genericIndex, bool isArray) - { - Type = default; - Handle = default; - GenericIndex = genericIndex; - IsArray = isArray; - } - - public bool IsHandle() - { - return Handle != default; - } - - public bool IsGeneric() - { - return GenericIndex != -1; - } - } - - class TypeDeclaration - { - public readonly ISymbol Node; - public TypeDefinitionHandle Handle; - public string DefaultInterface; - public string StaticInterface; - public bool IsSynthesizedInterface; - public bool IsComponentType; - - public Dictionary> MethodDefinitions = new(SymbolEqualityComparer.Default); - public Dictionary> MethodReferences = new(SymbolEqualityComparer.Default); - public Dictionary FieldDefinitions = new(SymbolEqualityComparer.Default); - public Dictionary PropertyDefinitions = new(SymbolEqualityComparer.Default); - public Dictionary EventDefinitions = new(SymbolEqualityComparer.Default); - public Dictionary InterfaceImplDefinitions = new(SymbolEqualityComparer.Default); - public Dictionary> MethodsByName = new Dictionary>(StringComparer.Ordinal); - public Dictionary OverloadedMethods = new(SymbolEqualityComparer.Default); - public List CustomMappedSymbols = new(); - public HashSet SymbolsWithAttributes = new(SymbolEqualityComparer.Default); - public Dictionary ClassInterfaceMemberMapping = new(SymbolEqualityComparer.Default); - - public TypeDeclaration() - : this(null) - { - IsSynthesizedInterface = true; - } - - public TypeDeclaration(ISymbol node, bool isComponentType = false) - { - Node = node; - Handle = default; - IsSynthesizedInterface = false; - IsComponentType = isComponentType; - } - - public override string ToString() - { - return Node.ToString(); - } - - public void AddMethod(ISymbol node, string name, MethodDefinitionHandle handle) - { - if (!MethodDefinitions.ContainsKey(node)) - { - MethodDefinitions[node] = new List(); - MethodReferences[node] = new List(); - } - - if (!MethodsByName.ContainsKey(name)) - { - MethodsByName[name] = new List(); - } - - MethodDefinitions[node].Add(handle); - MethodReferences[node].Add(handle); - MethodsByName[name].Add(node); - } - - public void AddMethodReference(ISymbol node, MemberReferenceHandle handle) - { - if (!MethodReferences.ContainsKey(node)) - { - MethodReferences[node] = new List(); - } - - MethodReferences[node].Add(handle); - } - - public void AddMethodOverload(ISymbol node, string overloadedMethodName) - { - OverloadedMethods[node] = overloadedMethodName; - } - - public List GetMethodDefinitions() - { - return MethodDefinitions.Values.SelectMany(list => list).ToList(); - } - - public List GetMethodReferences() - { - return MethodReferences.Values.SelectMany(list => list).ToList(); - } - - public void AddField(ISymbol node, FieldDefinitionHandle handle) - { - FieldDefinitions[node] = handle; - } - - public List GetFieldDefinitions() - { - return FieldDefinitions.Values.ToList(); - } - - public void AddProperty(ISymbol node, PropertyDefinitionHandle handle) - { - PropertyDefinitions[node] = handle; - } - - public List GetPropertyDefinitions() - { - return PropertyDefinitions.Values.ToList(); - } - - public void AddEvent(ISymbol node, EventDefinitionHandle handle) - { - EventDefinitions[node] = handle; - } - - public List GetEventDefinitions() - { - return EventDefinitions.Values.ToList(); - } - - public void AddInterfaceImpl(ISymbol node, InterfaceImplementationHandle handle) - { - InterfaceImplDefinitions[node] = handle; - } - - } - - class WinRTTypeWriter : CSharpSyntaxWalker - { - internal static readonly List ImplementedInterfacesWithoutMapping = new List() - { - "System.Collections.Generic.ICollection`1", - "System.Collections.Generic.IReadOnlyCollection`1", - "System.Collections.ICollection", - "System.Collections.IEnumerator", - "System.IEquatable`1", - "System.Runtime.InteropServices.ICustomQueryInterface", - "System.Runtime.InteropServices.IDynamicInterfaceCastable", - "WinRT.IWinRTObject" - }; - - public SemanticModel Model; - - private readonly string assembly; - private readonly string version; - - private readonly Dictionary typeReferenceMapping; - private readonly Dictionary assemblyReferenceMapping; - private readonly MetadataBuilder metadataBuilder; - private readonly TypeMapper mapper; - private readonly Dictionary typeDefinitionMapping; - private TypeDeclaration currentTypeDeclaration; - - private Logger Logger { get; } - - public WinRTTypeWriter( - string assembly, - string version, - MetadataBuilder metadataBuilder, - Logger logger, - TypeMapper mapper) - { - this.assembly = assembly; - this.version = version; - this.metadataBuilder = metadataBuilder; - Logger = logger; - this.mapper = mapper; - typeReferenceMapping = new Dictionary(StringComparer.Ordinal); - assemblyReferenceMapping = new Dictionary(StringComparer.Ordinal); - typeDefinitionMapping = new Dictionary(StringComparer.Ordinal); - - CreteAssembly(); - } - - private void CreteAssembly() - { - Logger.Log("Generating assembly " + assembly + " version " + version); - metadataBuilder.AddAssembly( - metadataBuilder.GetOrAddString(assembly), - new Version(version), - default, - default, - AssemblyFlags.WindowsRuntime, - AssemblyHashAlgorithm.Sha1); - - var moduleDefinition = metadataBuilder.AddModule( - 0, - metadataBuilder.GetOrAddString(assembly + ".winmd"), - metadataBuilder.GetOrAddGuid(Guid.NewGuid()), - default, - default); - assemblyReferenceMapping[assembly] = moduleDefinition; - - metadataBuilder.AddTypeDefinition( - default, - default, - metadataBuilder.GetOrAddString(""), - default, - MetadataTokens.FieldDefinitionHandle(1), - MetadataTokens.MethodDefinitionHandle(1)); - } - - private bool IsEncodableAsSpecialType(SpecialType specialType) - { - return specialType != SpecialType.None && specialType <= SpecialType.System_Array; - } - - private void EncodeSpecialType(SpecialType specialType, SignatureTypeEncoder typeEncoder) - { - switch (specialType) - { - case SpecialType.System_Boolean: - typeEncoder.Boolean(); - break; - case SpecialType.System_Byte: - typeEncoder.Byte(); - break; - case SpecialType.System_Int16: - typeEncoder.Int16(); - break; - case SpecialType.System_Int32: - typeEncoder.Int32(); - break; - case SpecialType.System_Int64: - typeEncoder.Int64(); - break; - case SpecialType.System_UInt16: - typeEncoder.UInt16(); - break; - case SpecialType.System_UInt32: - typeEncoder.UInt32(); - break; - case SpecialType.System_UInt64: - typeEncoder.UInt64(); - break; - case SpecialType.System_Single: - typeEncoder.Single(); - break; - case SpecialType.System_Double: - typeEncoder.Double(); - break; - case SpecialType.System_Char: - typeEncoder.Char(); - break; - case SpecialType.System_String: - typeEncoder.String(); - break; - case SpecialType.System_Object: - typeEncoder.Object(); - break; - case SpecialType.System_IntPtr: - typeEncoder.IntPtr(); - break; - default: - Logger.Log("TODO special type: " + specialType); - break; - } - - // TODO: handle C# interface mappings for special types - } - - private BlobHandle GetStrongNameKey(string assembly) - { - if (string.CompareOrdinal(assembly, "mscorlib") == 0) - { - byte[] mscorlibStrongName = { 0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89 }; - return metadataBuilder.GetOrAddBlob(mscorlibStrongName); - } - - return default; - } - - private EntityHandle GetTypeReference(string @namespace, string name, string assembly) - { - string fullname = QualifiedName(@namespace, name); - if (typeReferenceMapping.ContainsKey(fullname)) - { - return typeReferenceMapping[fullname]; - } - - if (!assemblyReferenceMapping.ContainsKey(assembly)) - { - EntityHandle assemblyReference = metadataBuilder.AddAssemblyReference( - metadataBuilder.GetOrAddString(assembly), - new Version(0xff, 0xff, 0xff, 0xff), - default, - GetStrongNameKey(assembly), - string.CompareOrdinal(assembly, "mscorlib") == 0 ? default : AssemblyFlags.WindowsRuntime, - default); - assemblyReferenceMapping[assembly] = assemblyReference; - } - - var typeRef = metadataBuilder.AddTypeReference( - assemblyReferenceMapping[assembly], - metadataBuilder.GetOrAddString(@namespace), - metadataBuilder.GetOrAddString(name)); - typeReferenceMapping[fullname] = typeRef; - return typeRef; - } - - public string GetAssemblyForWinRTType(ISymbol type) - { - var winrtTypeAttribute = type.GetAttributes(). - Where(attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeTypeAttribute") == 0); - if (winrtTypeAttribute.Any()) - { - return (string)winrtTypeAttribute.First().ConstructorArguments[0].Value; - } - - return null; - } - - private EntityHandle GetTypeReference(ISymbol symbol) - { - string @namespace = symbol.ContainingNamespace.ToString(); - string name = GetGenericName(symbol); - - string fullType = QualifiedName(@namespace, name); - var assembly = GetAssemblyForWinRTType(symbol); - if (assembly == null) - { - if (mapper.HasMappingForType(fullType)) - { - (@namespace, name, assembly, _, _) = mapper.GetMappedType(fullType).GetMapping(currentTypeDeclaration.Node); - Logger.Log("custom mapping " + fullType + " to " + QualifiedName(@namespace, name) + " from " + assembly); - } - else - { - assembly = symbol.ContainingAssembly.Name; - } - } - - return GetTypeReference(@namespace, name, assembly); - } - - private EntityHandle GetTypeSpecification(INamedTypeSymbol symbol) - { - if (symbol.IsGenericType) - { - Logger.Log("Adding TypeSpec for " + symbol.ToString()); - var typeSpecSignature = new BlobBuilder(); - var genericType = new BlobEncoder(typeSpecSignature) - .TypeSpecificationSignature() - .GenericInstantiation(GetTypeReference(symbol), symbol.TypeArguments.Length, false); - foreach (var typeArgument in symbol.TypeArguments) - { - EncodeSymbol(new Symbol(typeArgument), genericType.AddArgument()); - } - - return metadataBuilder.AddTypeSpecification(metadataBuilder.GetOrAddBlob(typeSpecSignature)); - } - else - { - return GetTypeReference(symbol); - } - } - - private void EncodeSymbol(Symbol symbol, SignatureTypeEncoder typeEncoder) - { - if (symbol.IsHandle()) - { - typeEncoder.Type(symbol.Handle, false); - } - else if (symbol.IsGeneric()) - { - if (symbol.IsArray) - { - typeEncoder.SZArray().GenericTypeParameter(symbol.GenericIndex); - } - else - { - typeEncoder.GenericTypeParameter(symbol.GenericIndex); - } - } - else if (symbol.IsArray) - { - EncodeSymbol(new Symbol(symbol.Type), typeEncoder.SZArray()); - } - else if (symbol.Type is IArrayTypeSymbol arrayType) - { - EncodeSymbol(new Symbol(arrayType.ElementType), typeEncoder.SZArray()); - } - else if (symbol.Type is INamedTypeSymbol namedType && namedType.TypeArguments.Length != 0) - { - var genericType = typeEncoder.GenericInstantiation(GetTypeReference(symbol.Type), namedType.TypeArguments.Length, false); - int parameterIndex = 0; - foreach (var typeArgument in namedType.TypeArguments) - { - if (namedType.IsUnboundGenericType) - { - genericType.AddArgument().GenericTypeParameter(parameterIndex); - } - else - { - EncodeSymbol(new Symbol(typeArgument), genericType.AddArgument()); - } - parameterIndex++; - } - } - else if (IsEncodableAsSpecialType(symbol.Type.SpecialType)) - { - EncodeSpecialType(symbol.Type.SpecialType, typeEncoder); - } - else - { - bool isValueType = symbol.Type.TypeKind == TypeKind.Enum || symbol.Type.TypeKind == TypeKind.Struct; - if (mapper.HasMappingForType(QualifiedName(symbol.Type))) - { - (_, _, _, _, isValueType) = mapper.GetMappedType(QualifiedName(symbol.Type)).GetMapping(currentTypeDeclaration.Node); - } - typeEncoder.Type(GetTypeReference(symbol.Type), isValueType); - } - } - - private void EncodeReturnType(Symbol symbol, ReturnTypeEncoder returnTypeEncoder) - { - if (symbol == null) - { - returnTypeEncoder.Void(); - } - else if (symbol.IsHandle() || symbol.IsGeneric() || !IsEncodableAsSpecialType(symbol.Type.SpecialType)) - { - EncodeSymbol(symbol, returnTypeEncoder.Type()); - } - else if (symbol.Type.SpecialType == SpecialType.System_Void) - { - returnTypeEncoder.Void(); - } - else - { - EncodeSpecialType(symbol.Type.SpecialType, returnTypeEncoder.Type()); - } - } - - private void EncodeParameters(Parameter[] parameters, ParametersEncoder parametersEncoder) - { - foreach (var parameter in parameters) - { - var parameterType = parameter.Type; - var parameterTypeEncoder = parametersEncoder.AddParameter(); - - if (!parameterType.IsHandle() && !parameterType.IsGeneric() && IsEncodableAsSpecialType(parameterType.Type.SpecialType)) - { - EncodeSpecialType(parameterType.Type.SpecialType, parameterTypeEncoder.Type(parameter.ByRef)); - } - else - { - EncodeSymbol(parameterType, parameterTypeEncoder.Type(parameter.ByRef)); - } - } - } - - public MethodDefinitionHandle AddMethodDefinition( - string name, - Parameter[] parameters, - Symbol returnSymbol, - bool isStatic, - bool isInterfaceParent, - bool isSpecialMethod = false, - bool isPublic = true, - bool isOverridable = false) - { - var methodSignature = new BlobBuilder(); - new BlobEncoder(methodSignature) - .MethodSignature( - SignatureCallingConvention.Default, - 0, - !isStatic) - .Parameters( - parameters.Length, - returnType => EncodeReturnType(returnSymbol, returnType), - parametersEncoder => EncodeParameters(parameters, parametersEncoder) - ); - - List parameterHandles = new List(); - for (int idx = 0; idx < parameters.Length; idx++) - { - parameterHandles.Add(metadataBuilder.AddParameter( - parameters[idx].Attributes, - metadataBuilder.GetOrAddString(parameters[idx].Name), - idx + 1)); - } - - var methodAttributes = - (isPublic ? MethodAttributes.Public : MethodAttributes.Private) | - MethodAttributes.HideBySig; - - var methodImplAttributes = MethodImplAttributes.Managed; - - if (isInterfaceParent) - { - methodAttributes |= MethodAttributes.Abstract; - } - else - { - methodImplAttributes |= MethodImplAttributes.Runtime; - } - - if (isSpecialMethod && string.CompareOrdinal(name, ".ctor") == 0) - { - methodAttributes |= MethodAttributes.RTSpecialName; - } - else if (isStatic) - { - methodAttributes |= MethodAttributes.Static; - } - else - { - methodAttributes |= - MethodAttributes.Virtual | - MethodAttributes.NewSlot; - - if (!isOverridable && !isInterfaceParent) - { - methodAttributes |= MethodAttributes.Final; - } - } - - if (isSpecialMethod) - { - methodAttributes |= MethodAttributes.SpecialName; - } - - var methodDefinitionHandle = metadataBuilder.AddMethodDefinition( - methodAttributes, - methodImplAttributes, - metadataBuilder.GetOrAddString(name), - metadataBuilder.GetOrAddBlob(methodSignature), - -1, - parameterHandles.Count == 0 ? - MetadataTokens.ParameterHandle(metadataBuilder.GetRowCount(TableIndex.Param) + 1) : - parameterHandles[0]); - return methodDefinitionHandle; - } - - public void AddFieldDeclaration(IFieldSymbol field, bool isEnum) - { - Logger.Log("defining field " + field.Name + " with type " + field.Type.ToString()); - - var fieldSignature = new BlobBuilder(); - var encoder = new BlobEncoder(fieldSignature); - EncodeSymbol(new Symbol(field.Type), encoder.FieldSignature()); - - var fieldAttributes = FieldAttributes.Public; - if (isEnum) - { - fieldAttributes |= - FieldAttributes.Static | - FieldAttributes.Literal | - FieldAttributes.HasDefault; - } - - var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( - fieldAttributes, - metadataBuilder.GetOrAddString(field.Name), - metadataBuilder.GetOrAddBlob(fieldSignature)); - currentTypeDeclaration.AddField(field, fieldDefinitionHandle); - - if (isEnum && field.HasConstantValue) - { - metadataBuilder.AddConstant(fieldDefinitionHandle, field.ConstantValue); - } - } - - public void AddPropertyDefinition( - string propertyName, - Symbol type, - ISymbol symbol, - bool isStatic, - bool hasSetMethod, - bool isInterfaceParent, - bool isPublic = true) - { - Logger.Log("defining property " + propertyName); - GetNamespaceAndTypename(propertyName, out var @namespace, out var typename); - - var propertySignature = new BlobBuilder(); - new BlobEncoder(propertySignature) - .PropertySignature(!isStatic) - .Parameters( - 0, - returnType => EncodeReturnType(type, returnType), - parameters => { } - ); - - var propertyDefinitonHandle = metadataBuilder.AddProperty( - PropertyAttributes.None, - metadataBuilder.GetOrAddString(propertyName), - metadataBuilder.GetOrAddBlob(propertySignature)); - currentTypeDeclaration.AddProperty(symbol, propertyDefinitonHandle); - - if (hasSetMethod) - { - string setMethodName = QualifiedName(@namespace, "put_" + typename); - var setMethod = AddMethodDefinition( - setMethodName, - new Parameter[] { new Parameter(type, "value", ParameterAttributes.In) }, - null, - !isInterfaceParent && isStatic, - isInterfaceParent, - true, - isPublic); - currentTypeDeclaration.AddMethod(symbol, setMethodName, setMethod); - - metadataBuilder.AddMethodSemantics( - propertyDefinitonHandle, - MethodSemanticsAttributes.Setter, - setMethod); - } - - string getMethodName = QualifiedName(@namespace, "get_" + typename); - var getMethod = AddMethodDefinition( - getMethodName, - new Parameter[0], - type, - !isInterfaceParent && isStatic, - isInterfaceParent, - true, - isPublic); - currentTypeDeclaration.AddMethod(symbol, getMethodName, getMethod); - - metadataBuilder.AddMethodSemantics( - propertyDefinitonHandle, - MethodSemanticsAttributes.Getter, - getMethod); - } - - public void AddPropertyDeclaration(IPropertySymbol property, bool isInterfaceParent) - { - AddPropertyDefinition( - property.Name, - new Symbol(property.Type), - property, - property.IsStatic, - property.SetMethod != null && - (property.SetMethod.DeclaredAccessibility == Accessibility.Public || - !property.SetMethod.ExplicitInterfaceImplementations.IsDefaultOrEmpty), - isInterfaceParent, - property.ExplicitInterfaceImplementations.IsDefaultOrEmpty); - } - - private TypeDefinitionHandle AddTypeDefinition( - TypeAttributes typeAttributes, - string @namespace, - string identifier, - EntityHandle baseType) - { - var fieldDefinitions = currentTypeDeclaration.GetFieldDefinitions(); - var methodDefinitions = currentTypeDeclaration.GetMethodDefinitions(); - - var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( - typeAttributes, - metadataBuilder.GetOrAddString(@namespace), - metadataBuilder.GetOrAddString(identifier), - baseType, - fieldDefinitions.Count == 0 ? - MetadataTokens.FieldDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.Field) + 1) : - fieldDefinitions[0], - methodDefinitions.Count == 0 ? - MetadataTokens.MethodDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.MethodDef) + 1) : - methodDefinitions[0] - ); - - var propertyDefinitions = currentTypeDeclaration.GetPropertyDefinitions(); - if (propertyDefinitions.Count != 0) - { - metadataBuilder.AddPropertyMap( - typeDefinitionHandle, - propertyDefinitions[0]); - } - - var eventDefinitions = currentTypeDeclaration.GetEventDefinitions(); - if (eventDefinitions.Count != 0) - { - metadataBuilder.AddEventMap( - typeDefinitionHandle, - eventDefinitions[0]); - } - - return typeDefinitionHandle; - } - - private void ProcessCustomMappedInterfaces(INamedTypeSymbol classSymbol) - { - Logger.Log("writing custom mapped interfaces for " + QualifiedName(classSymbol)); - Dictionary isPublicImplementation = new(SymbolEqualityComparer.Default); - - // Mark custom mapped interface members for removal later. - // Note we want to also mark members from interfaces without mappings. - foreach (var implementedInterface in GetInterfaces(classSymbol, true). - Where(symbol => mapper.HasMappingForType(QualifiedName(symbol)) || - ImplementedInterfacesWithoutMapping.Contains(QualifiedName(symbol)))) - { - bool isPubliclyImplemented = false; - Logger.Log("custom mapped interface: " + QualifiedName(implementedInterface, true)); - foreach (var interfaceMember in implementedInterface.GetMembers()) - { - var classMember = classSymbol.FindImplementationForInterfaceMember(interfaceMember); - currentTypeDeclaration.CustomMappedSymbols.Add(classMember); - - // For custom mapped interfaces, we don't have 1 to 1 mapping of members between the mapped from - // and mapped to interface and due to that we need to decide if the mapped inteface as a whole - // is public or not (explicitly implemented). Due to that, as long as one member is not - // explicitly implemented (i.e accessible via the class), we treat the entire mapped interface - // also as accessible via the class. - isPubliclyImplemented |= (classMember.DeclaredAccessibility == Accessibility.Public); - } - isPublicImplementation[implementedInterface] = isPubliclyImplemented; - } - - foreach (var implementedInterface in GetInterfaces(classSymbol) - .Where(symbol => mapper.HasMappingForType(QualifiedName(symbol)))) - { - WriteCustomMappedTypeMembers(implementedInterface, true, isPublicImplementation[implementedInterface]); - } - } - - INamedTypeSymbol GetTypeByMetadataName(string metadataName) - { - var namedType = Model.Compilation.GetTypeByMetadataName(metadataName); - if (namedType != null) - { - return namedType; - } - - // Model.Compilation.GetTypeByMetadataName doesn't return a type if there is multiple references with the same type. - // So as a fallback, go through all the references and check each one filtering to public ones. - var types = Model.Compilation.References - .Select(Model.Compilation.GetAssemblyOrModuleSymbol) - .OfType() - .Select(assemblySymbol => assemblySymbol.GetTypeByMetadataName(metadataName)) - .Where(type => type != null && type.DeclaredAccessibility == Accessibility.Public); - return types.FirstOrDefault(); - } - - // Convert the entire type name including the generic types to WinMD format. - private string GetMappedQualifiedTypeName(ITypeSymbol symbol) - { - string qualifiedName = QualifiedName(symbol); - if (mapper.HasMappingForType(qualifiedName)) - { - var (@namespace, mappedTypeName, _, _, _) = mapper.GetMappedType(qualifiedName).GetMapping(currentTypeDeclaration.Node); - qualifiedName = QualifiedName(@namespace, mappedTypeName); - if (symbol is INamedTypeSymbol namedType && namedType.TypeArguments.Length > 0) - { - return string.Format("{0}<{1}>", qualifiedName, string.Join(", ", namedType.TypeArguments.Select(type => GetMappedQualifiedTypeName(type)))); - } - } - else if ((string.CompareOrdinal(symbol.ContainingNamespace.ToString(), "System") == 0 && - symbol.IsValueType) || string.CompareOrdinal(qualifiedName, "System.String") == 0) - { - // WinRT fundamental types - return symbol.Name; - } - - return qualifiedName; - } - - private void WriteCustomMappedTypeMembers(INamedTypeSymbol symbol, bool isDefinition, bool isPublic = true) - { - var (_, mappedTypeName, _, _, _) = mapper.GetMappedType(QualifiedName(symbol)).GetMapping(currentTypeDeclaration.Node); - string qualifiedName = GetMappedQualifiedTypeName(symbol); - - Logger.Log("writing custom mapped type members for " + mappedTypeName + " public: " + isPublic + " qualified name: " + qualifiedName); - void AddMethod(string name, Parameter[] parameters, Symbol returnType) - { - parameters ??= new Parameter[0]; - if (isDefinition) - { - var methodName = isPublic ? name : QualifiedName(qualifiedName, name); - var methodDefinitionHandle = AddMethodDefinition(methodName, parameters, returnType, false, false, false, isPublic); - currentTypeDeclaration.AddMethod(symbol, methodName, methodDefinitionHandle); - } - else - { - var memberReferenceHandle = AddMethodReference(name, parameters, returnType, symbol, false); - currentTypeDeclaration.AddMethodReference(symbol, memberReferenceHandle); - } - } - - void AddProperty(string name, Symbol type, bool setProperty) - { - if (isDefinition) - { - var propertyName = isPublic ? name : QualifiedName(qualifiedName, name); - AddPropertyDefinition(propertyName, type, symbol, false, setProperty, false, isPublic); - } - else - { - AddPropertyReference(name, type, symbol, symbol, setProperty); - } - } - - void AddEvent(string name, Symbol eventType) - { - if (isDefinition) - { - var eventName = isPublic ? name : QualifiedName(qualifiedName, name); - AddEventDeclaration(eventName, eventType.Type, symbol, false, false, isPublic); - } - else - { - AddEventReference(name, eventType.Type, symbol, symbol); - } - } - - Symbol GetType(string type, bool isGeneric = false, int genericIndex = -1, bool isArray = false, ITypeSymbol[] genericTypes = null) - { - if (string.IsNullOrEmpty(type) && isGeneric) - { - return isDefinition ? new Symbol(symbol.TypeArguments[genericIndex], isArray) : new Symbol(genericIndex, isArray); - } - - var namedTypeSymbol = GetTypeByMetadataName(type); - if (!isGeneric) - { - return new Symbol(namedTypeSymbol, isArray); - } - - if (isDefinition) - { - var typeArguments = genericTypes ?? ((genericIndex == -1) ? - symbol.TypeArguments.ToArray() : new ITypeSymbol[] { symbol.TypeArguments[genericIndex] }); - return new Symbol(namedTypeSymbol.Construct(typeArguments), isArray); - } - else - { - return new Symbol(namedTypeSymbol.ConstructUnboundGenericType(), isArray); - } - } - - if (string.CompareOrdinal(mappedTypeName, "IClosable") == 0) - { - AddMethod("Close", null, null); - } - else if (string.CompareOrdinal(mappedTypeName, "IIterable`1") == 0) - { - AddMethod("First", null, GetType("System.Collections.Generic.IEnumerator`1", true)); - } - else if (string.CompareOrdinal(mappedTypeName, "IMap`2") == 0) - { - AddMethod("Clear", null, null); - AddMethod("GetView", null, GetType("System.Collections.Generic.IReadOnlyDictionary`2", true)); - AddMethod( - "HasKey", - new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, - GetType("System.Boolean") - ); - AddMethod( - "Insert", - new[] { - new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In), - new Parameter(GetType(null, true, 1), "value", ParameterAttributes.In) - }, - GetType("System.Boolean") - ); - AddMethod( - "Lookup", - new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, - GetType(null, true, 1) - ); - AddMethod( - "Remove", - new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, - null - ); - AddProperty("Size", GetType("System.UInt32"), false); - } - else if (string.CompareOrdinal(mappedTypeName, "IMapView`2") == 0) - { - AddMethod( - "HasKey", - new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, - GetType("System.Boolean") - ); - AddMethod( - "Lookup", - new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, - GetType(null, true, 1) - ); - AddMethod( - "Split", - new[] { - new Parameter(GetType("System.Collections.Generic.IReadOnlyDictionary`2", true), "first", ParameterAttributes.Out), - new Parameter(GetType("System.Collections.Generic.IReadOnlyDictionary`2", true), "second", ParameterAttributes.Out) - }, - null - ); - AddProperty("Size", GetType("System.UInt32"), false); - } - else if (string.CompareOrdinal(mappedTypeName, "IIterator`1") == 0) - { - // make array - AddMethod( - "GetMany", - new[] { new Parameter(GetType(null, true, 0, true), "items", ParameterAttributes.In, false) }, - GetType("System.UInt32") - ); - AddMethod( - "MoveNext", - null, - GetType("System.Boolean") - ); - AddProperty("Current", GetType(null, true, 0), false); - AddProperty("HasCurrent", GetType("System.Boolean"), false); - } - else if (string.CompareOrdinal(mappedTypeName, "IVector`1") == 0) - { - AddMethod( - "Append", - new[] { new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In) }, - null - ); - AddMethod("Clear", null, null); - AddMethod( - "GetAt", - new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, - GetType(null, true, 0) - ); - AddMethod( - "GetMany", - new[] { - new Parameter(GetType("System.UInt32"), "startIndex", ParameterAttributes.In), - new Parameter(GetType(null, true, 0, true), "items", ParameterAttributes.In) - }, - GetType("System.UInt32") - ); - AddMethod("GetView", null, GetType("System.Collections.Generic.IReadOnlyList`1", true)); - AddMethod( - "IndexOf", - new[] { - new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In), - new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.Out) - }, - GetType("System.Boolean") - ); - AddMethod( - "InsertAt", - new[] { - new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In), - new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In), - }, - null - ); - AddMethod( - "RemoveAt", - new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, - null - ); - AddMethod("RemoveAtEnd", null, null); - AddMethod( - "ReplaceAll", - new[] { - new Parameter(GetType(null, true, 0, true), "items", ParameterAttributes.In) - }, - null - ); - AddMethod( - "SetAt", - new[] { - new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In), - new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In), - }, - null - ); - AddProperty("Size", GetType("System.UInt32"), false); - } - else if (string.CompareOrdinal(mappedTypeName, "IVectorView`1") == 0) - { - AddMethod( - "GetAt", - new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, - GetType(null, true, 0) - ); - AddMethod( - "GetMany", - new[] { - new Parameter(GetType("System.UInt32"), "startIndex", ParameterAttributes.In), - new Parameter(GetType(null, true, 0, true), "items", ParameterAttributes.In) - }, - GetType("System.UInt32") - ); - AddMethod( - "IndexOf", - new[] { - new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In), - new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.Out) - }, - GetType("System.Boolean") - ); - AddProperty("Size", GetType("System.UInt32"), false); - } - else if (string.CompareOrdinal(mappedTypeName, "IXamlServiceProvider") == 0) - { - AddMethod( - "GetService", - new[] { new Parameter(GetType("System.Type"), "type", ParameterAttributes.In) }, - GetType("System.Object") - ); - } - else if (string.CompareOrdinal(mappedTypeName, "INotifyDataErrorInfo") == 0) - { - AddProperty("HasErrors", GetType("System.Boolean"), false); - AddEvent( - "ErrorsChanged", - GetType("System.EventHandler`1", true, -1, false, new[] { GetType("System.ComponentModel.DataErrorsChangedEventArgs").Type })); - AddMethod( - "GetErrors", - new[] { new Parameter(GetType("System.String"), "propertyName", ParameterAttributes.In) }, - GetType("System.Collections.Generic.IEnumerable`1", true, -1, false, new[] { GetType("System.Object").Type }) - ); - } - else if (string.CompareOrdinal(mappedTypeName, "INotifyPropertyChanged") == 0) - { - AddEvent("PropertyChanged", GetType("System.ComponentModel.PropertyChangedEventHandler")); - } - else if (string.CompareOrdinal(mappedTypeName, "ICommand") == 0) - { - AddEvent( - "CanExecuteChanged", - GetType("System.EventHandler`1", true, -1, false, new[] { GetType("System.Object").Type })); - AddMethod( - "CanExecute", - new[] { new Parameter(GetType("System.Object"), "parameter", ParameterAttributes.In) }, - GetType("System.Boolean") - ); - AddMethod( - "Execute", - new[] { new Parameter(GetType("System.Object"), "parameter", ParameterAttributes.In) }, - null - ); - } - else if (string.CompareOrdinal(mappedTypeName, "IBindableIterable") == 0) - { - AddMethod("First", null, GetType("Microsoft.UI.Xaml.Interop.IBindableIterator")); - } - else if (string.CompareOrdinal(mappedTypeName, "IBindableVector") == 0) - { - AddMethod( - "Append", - new[] { new Parameter(GetType("System.Object"), "value", ParameterAttributes.In) }, - null - ); - AddMethod("Clear", null, null); - AddMethod( - "GetAt", - new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, - GetType("System.Object") - ); - AddMethod("GetView", null, GetType("Microsoft.UI.Xaml.Interop.IBindableVectorView")); - AddMethod( - "IndexOf", - new[] { - new Parameter(GetType("System.Object"), "value", ParameterAttributes.In), - new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.Out) - }, - GetType("System.Boolean") - ); - AddMethod( - "InsertAt", - new[] { - new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In), - new Parameter(GetType("System.Object"), "value", ParameterAttributes.In), - }, - null - ); - AddMethod( - "RemoveAt", - new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, - null - ); - AddMethod("RemoveAtEnd", null, null); - AddMethod( - "SetAt", - new[] { - new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In), - new Parameter(GetType("System.Object"), "value", ParameterAttributes.In), - }, - null - ); - AddProperty("Size", GetType("System.UInt32"), false); - } - else if (string.CompareOrdinal(mappedTypeName, "INotifyCollectionChanged") == 0) - { - AddEvent("CollectionChanged", GetType("System.Collections.Specialized.NotifyCollectionChangedEventHandler")); - } - } - - private IEnumerable GetInterfaces(INamedTypeSymbol symbol, bool includeInterfacesWithoutMappings = false) - { - HashSet interfaces = new(SymbolEqualityComparer.Default); - - // Gather all interfaces that are publicly accessible. We specifically need to exclude interfaces - // that are not public, as eg. those might be used for additional cloaked WinRT/COM interfaces. - // Ignoring them here makes sure that they're not processed to be part of the .winmd file. - void GatherPubliclyAccessibleInterfaces(ITypeSymbol symbol) - { - foreach (var @interface in symbol.Interfaces) - { - if (@interface.IsPubliclyAccessible()) - { - _ = interfaces.Add(@interface); - } - - // We're not using AllInterfaces on purpose: we only want to gather all interfaces but not - // from the base type. That's handled below to skip types that are already WinRT projections. - foreach (var @interface2 in @interface.AllInterfaces) - { - if (@interface2.IsPubliclyAccessible()) - { - _ = interfaces.Add(@interface2); - } - } - } - } - - GatherPubliclyAccessibleInterfaces(symbol); - - var baseType = symbol.BaseType; - while (baseType != null && !GeneratorHelper.IsWinRTType(baseType, mapper)) - { - GatherPubliclyAccessibleInterfaces(baseType); - - baseType = baseType.BaseType; - } - - // If the generic enumerable is implemented, don't implement the non generic one to prevent issues - // with the interface members being implemented multiple times. - if (!includeInterfacesWithoutMappings && - interfaces.Any(@interface => string.CompareOrdinal(QualifiedName(@interface), "System.Collections.Generic.IEnumerable`1") == 0)) - { - interfaces.Remove(GetTypeByMetadataName("System.Collections.IEnumerable")); - } - - return interfaces.Where(@interface => - includeInterfacesWithoutMappings || - !ImplementedInterfacesWithoutMapping.Contains(QualifiedName(@interface))) - .OrderBy(implementedInterface => implementedInterface.ToString()); - } - - public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) - { - AddComponentType(Model.GetDeclaredSymbol(node), () => base.VisitInterfaceDeclaration(node)); - } - - public override void VisitClassDeclaration(ClassDeclarationSyntax node) - { - AddComponentType(Model.GetDeclaredSymbol(node), () => base.VisitClassDeclaration(node)); - } - - public override void VisitStructDeclaration(StructDeclarationSyntax node) - { - AddComponentType(Model.GetDeclaredSymbol(node), () => base.VisitStructDeclaration(node)); - } - - private void EncodeTypedConstant(TypedConstant constant, LiteralEncoder encoder) - { - Logger.Log("typed constant kind: " + constant.Kind); - Logger.Log("typed constant type: " + constant.Type); - Logger.Log("typed constant value: " + constant.Value); - - switch (constant.Kind) - { - case TypedConstantKind.Primitive: - encoder.Scalar().Constant(constant.Value); - break; - case TypedConstantKind.Enum: - encoder.Scalar().Constant(constant.Value); - - // This looks more correct, but the code above matches what the C# compiler produces. - // Eg. win32metadata does the same (see 'MetadataUtils.EncodeHelpers' in https://github.com/microsoft/win32metadata). - // encoder.TaggedScalar( - // type => type.Enum(constant.Type.ToString()), - // scalar => scalar.Constant(constant.Value) - // ); - - break; - case TypedConstantKind.Type: - encoder.Scalar().SystemType(constant.Value.ToString()); - break; - case TypedConstantKind.Array: - { - LiteralsEncoder arrayEncoder = encoder.Vector().Count(constant.Values.Length); - foreach (var arrayConstant in constant.Values) - { - EncodeTypedConstant(arrayConstant, arrayEncoder.AddLiteral()); - } - break; - } - } - } - - private void EncodeFixedArguments(IList arguments, FixedArgumentsEncoder argumentsEncoder) - { - foreach (var argument in arguments) - { - EncodeTypedConstant(argument, argumentsEncoder.AddArgument()); - } - } - - private void EncodeCustomElementType(ITypeSymbol type, CustomAttributeElementTypeEncoder typeEncoder) - { - switch (type.SpecialType) - { - case SpecialType.System_Boolean: - typeEncoder.Boolean(); - break; - case SpecialType.System_Byte: - typeEncoder.Byte(); - break; - case SpecialType.System_Int16: - typeEncoder.Int16(); - break; - case SpecialType.System_Int32: - typeEncoder.Int32(); - break; - case SpecialType.System_Int64: - typeEncoder.Int64(); - break; - case SpecialType.System_UInt16: - typeEncoder.UInt16(); - break; - case SpecialType.System_UInt32: - typeEncoder.UInt32(); - break; - case SpecialType.System_UInt64: - typeEncoder.UInt64(); - break; - case SpecialType.System_Single: - typeEncoder.Single(); - break; - case SpecialType.System_Double: - typeEncoder.Double(); - break; - case SpecialType.System_Char: - typeEncoder.Char(); - break; - case SpecialType.System_String: - typeEncoder.String(); - break; - case SpecialType.System_Enum: - typeEncoder.Enum(type.ToString()); - break; - case SpecialType.System_SByte: - typeEncoder.SByte(); - break; - default: - Logger.Log("TODO special type: " + type.SpecialType); - break; - } - } - - private void EncodeNamedArgumentType(ITypeSymbol type, NamedArgumentTypeEncoder encoder) - { - Logger.Log("encoding named type"); - if (type.SpecialType == SpecialType.System_Object) - { - encoder.Object(); - } - else if (type.SpecialType == SpecialType.System_Array) - { - // TODO array type encoder - encoder.SZArray(); - } - else - { - EncodeCustomElementType(type, encoder.ScalarType()); - } - } - - private ISymbol GetMember(INamedTypeSymbol type, string member) - { - var foundMembers = type.GetMembers(member); - var baseType = type.BaseType; - while (foundMembers.Count() == 0 && baseType != null) - { - foundMembers = baseType.GetMembers(member); - baseType = baseType.BaseType; - } - - Logger.Log("# members found: " + foundMembers.Count()); - var foundMember = foundMembers.First(); - Logger.Log("found member: " + foundMember); - return foundMember; - } - - private void EncodeNamedArguments( - INamedTypeSymbol attributeType, - IList> namedArguments, - CustomAttributeNamedArgumentsEncoder argumentsEncoder) - { - var encoder = argumentsEncoder.Count(namedArguments.Count); - foreach (var argument in namedArguments) - { - Logger.Log("named argument: " + argument.Key); - Logger.Log("value " + argument.Value); - - ITypeSymbol argumentType = null; - var attributeClassMember = GetMember(attributeType, argument.Key); - if (attributeClassMember is IFieldSymbol field) - { - argumentType = field.Type; - } - else if (attributeClassMember is IPropertySymbol property) - { - argumentType = property.Type; - } - else - { - Logger.Log("unexpected member: " + attributeClassMember.Name + " " + attributeClassMember.GetType()); - throw new InvalidOperationException(); - } - - encoder.AddArgument( - attributeClassMember is IFieldSymbol, - type => EncodeNamedArgumentType(argumentType, type), - name => name.Name(argument.Key), - literal => EncodeTypedConstant(argument.Value, literal) - ); - } - } - - private void EncodeFixedArguments(IList primitiveArguments, FixedArgumentsEncoder argumentsEncoder) - { - foreach (var argument in primitiveArguments) - { - var encoder = argumentsEncoder.AddArgument().Scalar(); - if (argument is string type) - { - encoder.SystemType(type); - } - else if (argument is INamedTypeSymbol namedTypeSymbol) - { - var typeEntity = GetTypeReference(namedTypeSymbol); - encoder.Builder.WriteReference(CodedIndex.TypeDefOrRef(typeEntity), false); - } - else - { - encoder.Constant(argument); - } - } - } - - private void AddDefaultVersionAttribute(EntityHandle parentHandle, int version = -1) - { - if (version == -1) - { - version = Version.Parse(this.version).Major; - } - - List types = new List - { - Model.Compilation.GetTypeByMetadataName("System.UInt32") - }; - - List arguments = new List - { - (UInt32) version - }; - - AddCustomAttributes("Windows.Foundation.Metadata.VersionAttribute", types, arguments, parentHandle); - } - - private void AddActivatableAttribute(EntityHandle parentHandle, UInt32 version, string factoryInterface) - { - List types = new List(2); - List arguments = new List(2); - - if (factoryInterface != null) - { - types.Add(Model.Compilation.GetTypeByMetadataName("System.Type")); - arguments.Add(factoryInterface); - } - types.Add(Model.Compilation.GetTypeByMetadataName("System.UInt32")); - arguments.Add(version); - - AddCustomAttributes("Windows.Foundation.Metadata.ActivatableAttribute", types, arguments, parentHandle); - } - - private void AddExclusiveToAttribute(EntityHandle interfaceHandle, string className) - { - List types = new List - { - Model.Compilation.GetTypeByMetadataName("System.Type") - }; - - List arguments = new List - { - className - }; - - AddCustomAttributes("Windows.Foundation.Metadata.ExclusiveToAttribute", types, arguments, interfaceHandle); - } - - private void AddStaticAttribute(EntityHandle parentHandle, UInt32 version, string staticInterface) - { - List types = new List - { - Model.Compilation.GetTypeByMetadataName("System.Type"), - Model.Compilation.GetTypeByMetadataName("System.UInt32") - }; - - List arguments = new List - { - staticInterface, - version - }; - - AddCustomAttributes("Windows.Foundation.Metadata.StaticAttribute", types, arguments, parentHandle); - } - - private void AddDefaultInterfaceImplAttribute(EntityHandle interfaceImplHandle) - { - AddCustomAttributes("Windows.Foundation.Metadata.DefaultAttribute", Array.Empty(), Array.Empty(), interfaceImplHandle); - } - - private void AddOverloadAttribute(EntityHandle methodHandle, string methodName) - { - List types = new List - { - Model.Compilation.GetTypeByMetadataName("System.String") - }; - - List arguments = new List - { - methodName - }; - - AddCustomAttributes("Windows.Foundation.Metadata.OverloadAttribute", types, arguments, methodHandle); - } - - private void AddOverloadAttributeForInterfaceMethods(TypeDeclaration interfaceTypeDeclaration) - { - // Generate unique names for any overloaded methods - foreach (var methodName in interfaceTypeDeclaration.MethodsByName.Where(symbol => symbol.Value.Count > 1)) - { - var methodSymbols = methodName.Value.Where(symbol => symbol is IMethodSymbol); - // Other members that are not methods such as properties and events can generate reserved methods - // which for the purposes of overloading are considered to be the non overloaded version. If there is no - // such function, then we consider the first encountered method to be the non overloaded version. - var skipFirstMethod = methodName.Value.Count == methodSymbols.Count(); - var lastSuffix = 1; - foreach (var method in methodSymbols) - { - if (skipFirstMethod) - { - skipFirstMethod = false; - continue; - } - - string overloadedMethodName = methodName.Key + (++lastSuffix); - while (interfaceTypeDeclaration.MethodsByName.ContainsKey(overloadedMethodName)) - { - overloadedMethodName = methodName.Key + (++lastSuffix); - } - - Logger.Log("Overloading " + methodName.Key + " with " + overloadedMethodName); - AddOverloadAttribute(interfaceTypeDeclaration.MethodDefinitions[method].First(), overloadedMethodName); - interfaceTypeDeclaration.AddMethodOverload(method, overloadedMethodName); - } - } - } - - private void AddGuidAttribute(EntityHandle parentHandle, Guid guid) - { - var uint32Type = Model.Compilation.GetTypeByMetadataName("System.UInt32"); - var uint16Type = Model.Compilation.GetTypeByMetadataName("System.UInt16"); - var byteType = Model.Compilation.GetTypeByMetadataName("System.Byte"); - List types = new List - { - uint32Type, - uint16Type, - uint16Type, - byteType, - byteType, - byteType, - byteType, - byteType, - byteType, - byteType, - byteType - }; - - var byteArray = guid.ToByteArray(); - List arguments = new List - { - BitConverter.ToUInt32(byteArray, 0), - BitConverter.ToUInt16(byteArray, 4), - BitConverter.ToUInt16(byteArray, 6), - byteArray[8], - byteArray[9], - byteArray[10], - byteArray[11], - byteArray[12], - byteArray[13], - byteArray[14], - byteArray[15] - }; - - AddCustomAttributes("Windows.Foundation.Metadata.GuidAttribute", types, arguments, parentHandle); - } - - private void AddGuidAttribute(EntityHandle parentHandle, string name) - { - Guid guid; - using (SHA1 sha = new SHA1CryptoServiceProvider()) - { - var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(name)); - guid = Helper.EncodeGuid(hash); - } - - AddGuidAttribute(parentHandle, guid); - } - - private void AddGuidAttribute(EntityHandle parentHandle, ISymbol symbol) - { - if (symbol.TryGetAttributeWithType(Model.Compilation.GetTypeByMetadataName("System.Runtime.InteropServices.GuidAttribute"), out AttributeData guidAttribute) - && guidAttribute is { ConstructorArguments.IsDefaultOrEmpty: false } - && guidAttribute.ConstructorArguments[0].Value is string guidString - && Guid.TryParse(guidString, out Guid guid)) - { - AddGuidAttribute(parentHandle, guid); - } - else - { - AddGuidAttribute(parentHandle, symbol.ToString()); - } - } - - private void AddCustomAttributes( - string attributeTypeName, - IList primitiveTypes, - IList primitiveValues, - EntityHandle parentHandle) - { - var attributeType = Model.Compilation.GetTypeByMetadataName(attributeTypeName); - Logger.Log("attribute type found " + attributeType); - if (!typeDefinitionMapping.ContainsKey(attributeTypeName)) - { - // Even if the attribute is an external non WinRT type, treat it as a projected type. - Logger.Log("adding attribute type"); - AddType(attributeType, true); - } - - Logger.Log("# constructor found: " + attributeType.Constructors.Length); - var matchingConstructor = attributeType.Constructors.Where(constructor => - constructor.Parameters.Length == primitiveValues.Count && - constructor.Parameters.Select(param => (param.Type is IErrorTypeSymbol) ? - Model.Compilation.GetTypeByMetadataName(param.Type.ToDisplayString()) : param.Type) - .SequenceEqual(primitiveTypes, SymbolEqualityComparer.Default)); - - Logger.Log("# matching constructor found: " + matchingConstructor.Count()); - Logger.Log("matching constructor found: " + matchingConstructor.First()); - - var constructorReference = typeDefinitionMapping[attributeTypeName].MethodReferences[matchingConstructor.First()]; - Logger.Log("found constructor handle: " + constructorReference.Count); - - var attributeSignature = new BlobBuilder(); - new BlobEncoder(attributeSignature) - .CustomAttributeSignature( - fixedArguments => EncodeFixedArguments(primitiveValues, fixedArguments), - namedArguments => namedArguments.Count(0) - ); - - metadataBuilder.AddCustomAttribute( - parentHandle, - constructorReference.First(), - metadataBuilder.GetOrAddBlob(attributeSignature)); - } - - private void AddCustomAttributes(IEnumerable attributes, EntityHandle parentHandle) - { - foreach (var attribute in attributes) - { - var attributeType = attribute.AttributeClass; - if (attributeType.DeclaredAccessibility != Accessibility.Public) - { - continue; - } - - if (attributeType.ToString() == "System.Runtime.InteropServices.GuidAttribute") - { - continue; - } - - // Skip the [GeneratedBindableCustomProperty] attribute. It is valid to add this on types in WinRT - // components (if they need to be exposed and implement ICustomPropertyProvider), but the attribute - // should never show up in the .winmd file (it would also cause build errors in the projections). - if (attributeType.ToString() == "WinRT.GeneratedBindableCustomPropertyAttribute") - { - continue; - } - - Logger.Log("attribute: " + attribute); - Logger.Log("attribute type: " + attributeType); - Logger.Log("attribute constructor: " + attribute.AttributeConstructor); - Logger.Log("atttribute # constructor arguments: " + attribute.ConstructorArguments.Length); - Logger.Log("atttribute # named arguments: " + attribute.NamedArguments.Length); - - if (!typeDefinitionMapping.ContainsKey(attributeType.ToString())) - { - // Even if the attribute is an external non WinRT type, treat it as a projected type. - AddType(attributeType, true); - } - - var constructorReference = typeDefinitionMapping[attributeType.ToString()].MethodReferences[attribute.AttributeConstructor]; - Logger.Log("found # constructors: " + constructorReference.Count); - - var attributeSignature = new BlobBuilder(); - new BlobEncoder(attributeSignature) - .CustomAttributeSignature( - fixedArguments => EncodeFixedArguments(attribute.ConstructorArguments, fixedArguments), - namedArguments => EncodeNamedArguments(attributeType, attribute.NamedArguments, namedArguments) - ); - - metadataBuilder.AddCustomAttribute( - parentHandle, - constructorReference.First(), - metadataBuilder.GetOrAddBlob(attributeSignature)); - } - } - - public override void VisitEnumDeclaration(EnumDeclarationSyntax node) - { - var symbol = Model.GetDeclaredSymbol(node); - - void processEnumDeclaration() - { - var enumTypeFieldAttributes = - FieldAttributes.Private | - FieldAttributes.SpecialName | - FieldAttributes.RTSpecialName; - - var enumTypeSymbol = symbol.EnumUnderlyingType; - var fieldSignature = new BlobBuilder(); - var encoder = new BlobEncoder(fieldSignature); - // TODO: special type enforcement for 64 bit - EncodeSpecialType(enumTypeSymbol.SpecialType, encoder.FieldSignature()); - - var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( - enumTypeFieldAttributes, - metadataBuilder.GetOrAddString("value__"), - metadataBuilder.GetOrAddBlob(fieldSignature)); - currentTypeDeclaration.AddField(symbol, fieldDefinitionHandle); - - base.VisitEnumDeclaration(node); - } - - AddComponentType(symbol, processEnumDeclaration); - } - - public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) - { - var symbol = Model.GetDeclaredSymbol(node); - if (!IsPublic(symbol)) - { - return; - } - - Logger.Log("defining delegate " + symbol.Name); - currentTypeDeclaration = new TypeDeclaration(symbol, true); - - base.VisitDelegateDeclaration(node); - CheckAndMarkSymbolForAttributes(symbol); - - var objType = Model.Compilation.GetTypeByMetadataName(typeof(object).FullName); - var nativeIntType = Model.Compilation.GetTypeByMetadataName(typeof(IntPtr).FullName); - - currentTypeDeclaration.AddMethod( - symbol, - ".ctor", - AddMethodDefinition( - ".ctor", - new Parameter[] { - new Parameter(objType, "object", ParameterAttributes.None), - new Parameter(nativeIntType, "method", ParameterAttributes.None) - }, - null, - false, - false, - true, - false, - true - ) - ); - - Parameter[] parameters = Parameter.GetParameters(node.ParameterList, Model); - currentTypeDeclaration.AddMethod( - symbol, - "Invoke", - AddMethodDefinition( - "Invoke", - parameters, - new Symbol(symbol.DelegateInvokeMethod.ReturnType), - false, - false, - true, - true, - true - ) - ); - - TypeAttributes typeAttributes = - TypeAttributes.Public | - TypeAttributes.WindowsRuntime | - TypeAttributes.AutoLayout | - TypeAttributes.AnsiClass | - TypeAttributes.Sealed; - - var typeDefinitionHandle = AddTypeDefinition( - typeAttributes, - symbol.ContainingNamespace.ToString(), - symbol.Name, - GetTypeReference("System", "MulticastDelegate", "mscorlib")); - currentTypeDeclaration.Handle = typeDefinitionHandle; - typeDefinitionMapping[QualifiedName(symbol, true)] = currentTypeDeclaration; - - AddGuidAttribute(typeDefinitionHandle, symbol); - } - - public void AddEventDeclaration(string eventName, ITypeSymbol eventType, ISymbol symbol, bool isStatic, bool isInterfaceParent, bool isPublic = true) - { - Logger.Log("defining event " + eventName + " with type " + eventType.ToString()); - - GetNamespaceAndTypename(eventName, out var @namespace, out var typename); - - var delegateSymbolType = eventType as INamedTypeSymbol; - EntityHandle typeReferenceHandle = GetTypeSpecification(delegateSymbolType); - EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); - Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); - - var eventDefinitionHandle = metadataBuilder.AddEvent( - EventAttributes.None, - metadataBuilder.GetOrAddString(eventName), - typeReferenceHandle); - currentTypeDeclaration.AddEvent(symbol, eventDefinitionHandle); - - string addMethodName = QualifiedName(@namespace, "add_" + typename); - var addMethod = AddMethodDefinition( - addMethodName, - new Parameter[] { new Parameter(delegateSymbolType, "handler", ParameterAttributes.In) }, - eventRegistrationToken, - !isInterfaceParent && isStatic, - isInterfaceParent, - true, - isPublic); - currentTypeDeclaration.AddMethod(symbol, addMethodName, addMethod); - - metadataBuilder.AddMethodSemantics( - eventDefinitionHandle, - MethodSemanticsAttributes.Adder, - addMethod); - - string removeMethodName = QualifiedName(@namespace, "remove_" + typename); - var removeMethod = AddMethodDefinition( - removeMethodName, - new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, - null, - !isInterfaceParent && isStatic, - isInterfaceParent, - true, - isPublic); - currentTypeDeclaration.AddMethod(symbol, removeMethodName, removeMethod); - - metadataBuilder.AddMethodSemantics( - eventDefinitionHandle, - MethodSemanticsAttributes.Remover, - removeMethod); - } - - public void AddEventDeclaration(IEventSymbol @event, bool isInterfaceParent) - { - AddEventDeclaration(@event.Name, @event.Type, @event, @event.IsStatic, isInterfaceParent, @event.ExplicitInterfaceImplementations.IsDefaultOrEmpty); - } - - void AddMethodDeclaration(IMethodSymbol method, bool isInterfaceParent) - { - Logger.Log("add method from symbol: " + method.Name); - - bool isConstructor = method.MethodKind == MethodKind.Constructor; - string methodName = isConstructor ? ".ctor" : method.Name; - var returnType = isConstructor ? null : new Symbol(method.ReturnType); - Parameter[] parameters = Parameter.GetParameters(method); - var methodDefinitionHandle = AddMethodDefinition( - methodName, - parameters, - returnType, - !isInterfaceParent && method.IsStatic, - isInterfaceParent, - isConstructor, - method.ExplicitInterfaceImplementations.IsDefaultOrEmpty); - currentTypeDeclaration.AddMethod(method, methodName, methodDefinitionHandle); - } - - void AddFactoryMethod(INamedTypeSymbol classSymbol, IMethodSymbol method) - { - Logger.Log("adding factory method: " + method.Name); - - string methodName = "Create" + classSymbol.Name; - Parameter[] parameters = Parameter.GetParameters(method); - var methodDefinitionHandle = AddMethodDefinition( - methodName, - parameters, - new Symbol(classSymbol), - false, - true, - false, - true, - true); - currentTypeDeclaration.AddMethod(method, methodName, methodDefinitionHandle); - } - - void AddComponentType(INamedTypeSymbol type, Action visitTypeDeclaration = null) - { - if (!IsPublic(type) || typeDefinitionMapping.ContainsKey(type.ToString())) - { - return; - } - - Logger.Log("defining type: " + type.TypeKind + " " + type.ToString()); - - var typeDeclaration = new TypeDeclaration(type, true); - currentTypeDeclaration = typeDeclaration; - - if (type.TypeKind == TypeKind.Class) - { - ProcessCustomMappedInterfaces(type); - } - - visitTypeDeclaration?.Invoke(); - CheckAndMarkSymbolForAttributes(type); - - bool isInterface = type.TypeKind == TypeKind.Interface; - bool hasConstructor = false; - bool hasAtLeastOneNonPublicConstructor = false; - bool hasDefaultConstructor = false; - foreach (var member in type.GetMembers()) - { - if (!IsPublic(member) || typeDeclaration.CustomMappedSymbols.Contains(member)) - { - Logger.Log(member.Kind + " member skipped " + member.Name); - - // We want to track whether a given public class has at least one non-public constructor. - // In this case, the class is still exposed to WinRT, but it's not activatable. This is - // different than a class with no explicit constructor, where we do want to generate that - // in the .winmd, and make the class activatable. But we want to avoid always emitting a - // default constructor for classes that only have non-public ones. - if (type.TypeKind == TypeKind.Class && - member is IMethodSymbol { MethodKind: MethodKind.Constructor }) - { - hasAtLeastOneNonPublicConstructor = true; - } - - continue; - } - - if (type.TypeKind == TypeKind.Struct || type.TypeKind == TypeKind.Enum) - { - if (member is IFieldSymbol field) - { - AddFieldDeclaration(field, type.TypeKind == TypeKind.Enum); - } - } - else - { - // Special case: skip members that are explicitly implementing internal interfaces. - // This allows implementing classic COM internal interfaces with non-WinRT signatures. - if (member.IsExplicitInterfaceImplementationOfInternalInterfaces()) - { - continue; - } - - if (member is IMethodSymbol method && - (method.MethodKind == MethodKind.Ordinary || - method.MethodKind == MethodKind.ExplicitInterfaceImplementation || - method.MethodKind == MethodKind.Constructor)) - { - AddMethodDeclaration(method, isInterface); - - if (method.MethodKind == MethodKind.Constructor) - { - hasConstructor = true; - hasDefaultConstructor |= (method.Parameters.Length == 0); - } - } - else if (member is IPropertySymbol property) - { - AddPropertyDeclaration(property, isInterface); - } - else if (member is IEventSymbol @event) - { - AddEventDeclaration(@event, isInterface); - } - else - { - Logger.Log("member not recognized: " + member.Kind + " name: " + member.Name); - continue; - } - } - - CheckAndMarkSymbolForAttributes(member); - } - - // Implicit constructor if none defined, but only if the type doesn't already have some non-public constructor - if (!hasConstructor && !hasAtLeastOneNonPublicConstructor && type.TypeKind == TypeKind.Class && !type.IsStatic) - { - string constructorMethodName = ".ctor"; - var methodDefinitionHandle = AddMethodDefinition( - constructorMethodName, - new Parameter[0], - null, - false, - false, - true, - true, - true); - typeDeclaration.AddMethod(type, constructorMethodName, methodDefinitionHandle); - hasDefaultConstructor = true; - } - - TypeAttributes typeAttributes = - TypeAttributes.Public | - TypeAttributes.WindowsRuntime | - TypeAttributes.AutoLayout | - TypeAttributes.AnsiClass; - - if (type.IsSealed || - type.IsStatic || - type.TypeKind == TypeKind.Struct || - type.TypeKind == TypeKind.Enum) - { - typeAttributes |= TypeAttributes.Sealed; - } - - if (type.TypeKind == TypeKind.Class && type.IsStatic) - { - typeAttributes |= TypeAttributes.Abstract; - } - - EntityHandle baseType = default; - if (isInterface) - { - typeAttributes |= - TypeAttributes.Interface | - TypeAttributes.Abstract; - } - else if (type.TypeKind == TypeKind.Class) - { - typeAttributes |= - TypeAttributes.Class | - TypeAttributes.BeforeFieldInit; - - // extends - // WinRT doesn't support projecting abstract classes. - // If the base class is one, ignore it. - if (type.BaseType != null && !type.BaseType.IsAbstract) - { - baseType = GetTypeReference(type.BaseType); - } - else - { - baseType = GetTypeReference("System", "Object", "mscorlib"); - } - } - else if (type.TypeKind == TypeKind.Struct) - { - typeAttributes |= TypeAttributes.SequentialLayout; - baseType = GetTypeReference("System", "ValueType", "mscorlib"); - } - else if (type.TypeKind == TypeKind.Enum) - { - baseType = GetTypeReference("System", "Enum", "mscorlib"); - } - - var typeDefinitionHandle = AddTypeDefinition( - typeAttributes, - type.ContainingNamespace.ToString(), - type.Name, - baseType); - typeDeclaration.Handle = typeDefinitionHandle; - - if (isInterface || type.TypeKind == TypeKind.Class) - { - // Interface implementations need to be added in order of class and then typespec. Given entries are added - // per class, that is already in order, but we need to sort by typespec. - List> implementedInterfaces = new List>(); - foreach (var implementedInterface in GetInterfaces(type)) - { - implementedInterfaces.Add(new KeyValuePair(implementedInterface, GetTypeSpecification(implementedInterface))); - } - implementedInterfaces.Sort((x, y) => CodedIndex.TypeDefOrRefOrSpec(x.Value).CompareTo(CodedIndex.TypeDefOrRefOrSpec(y.Value))); - - foreach (var implementedInterface in implementedInterfaces) - { - var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( - typeDefinitionHandle, - implementedInterface.Value); - typeDeclaration.AddInterfaceImpl(implementedInterface.Key, interfaceImplHandle); - } - } - - if (isInterface) - { - AddGuidAttribute(typeDefinitionHandle, type); - AddOverloadAttributeForInterfaceMethods(typeDeclaration); - } - - typeDefinitionMapping[QualifiedName(type, true)] = typeDeclaration; - - if (type.TypeKind == TypeKind.Class) - { - if (hasDefaultConstructor) - { - AddActivatableAttribute( - typeDeclaration.Handle, - (uint)GetVersion(type, true), - null); - } - AddSynthesizedInterfaces(typeDeclaration); - - // No synthesized default interface generated - if (typeDeclaration.DefaultInterface == null && type.Interfaces.Length != 0) - { - AddDefaultInterfaceImplAttribute(typeDeclaration.InterfaceImplDefinitions[type.Interfaces[0]]); - } - } - } - - MemberReferenceHandle AddMethodReference( - string name, - Parameter[] parameters, - Symbol returnSymbol, - INamedTypeSymbol parentType, - bool isStatic) - { - var methodSignature = new BlobBuilder(); - new BlobEncoder(methodSignature) - .MethodSignature( - SignatureCallingConvention.Default, - 0, - !isStatic) - .Parameters( - parameters.Length, - returnType => EncodeReturnType(returnSymbol, returnType), - parametersEncoder => EncodeParameters(parameters, parametersEncoder) - ); - - var referenceHandle = metadataBuilder.AddMemberReference( - GetTypeSpecification(parentType), - metadataBuilder.GetOrAddString(name), - metadataBuilder.GetOrAddBlob(methodSignature) - ); - return referenceHandle; - } - - MemberReferenceHandle AddMethodReference(IMethodSymbol method) - { - Logger.Log("adding method reference: " + method.Name); - - bool isInterfaceParent = method.ContainingType.TypeKind == TypeKind.Interface; - string methodName = method.MethodKind == MethodKind.Constructor ? ".ctor" : method.Name; - Parameter[] parameters = Parameter.GetParameters(method); - var referenceHandle = AddMethodReference( - methodName, - parameters, - new Symbol(method.ReturnType), - method.ContainingType, - !isInterfaceParent && method.IsStatic); - currentTypeDeclaration.AddMethodReference(method, referenceHandle); - return referenceHandle; - } - - public void AddPropertyReference(string name, Symbol type, ISymbol symbol, INamedTypeSymbol parent, bool setMethod) - { - Logger.Log("adding property reference: " + name); - - if (setMethod) - { - var setMethodReference = AddMethodReference( - "put_" + name, - new Parameter[] { new Parameter(type, "value", ParameterAttributes.In) }, - null, - parent, - false); - currentTypeDeclaration.AddMethodReference(symbol, setMethodReference); - } - - var getMethodReference = AddMethodReference( - "get_" + name, - new Parameter[0], - type, - parent, - false); - currentTypeDeclaration.AddMethodReference(symbol, getMethodReference); - } - - public void AddPropertyReference(IPropertySymbol property) - { - AddPropertyReference( - property.Name, - new Symbol(property.Type), - property, - property.ContainingType, - property.SetMethod != null); - } - - public void AddEventReference(string eventName, ITypeSymbol eventType, ISymbol symbol, INamedTypeSymbol parent) - { - Logger.Log("adding event reference: " + eventName); - - EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); - Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); - - var addMethodReference = AddMethodReference( - "add_" + eventName, - new Parameter[] { new Parameter(eventType, "handler", ParameterAttributes.In) }, - eventRegistrationToken, - parent, - false); - currentTypeDeclaration.AddMethodReference(symbol, addMethodReference); - - var removeMethodReference = AddMethodReference( - "remove_" + eventName, - new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, - null, - parent, - false); - currentTypeDeclaration.AddMethodReference(symbol, removeMethodReference); - } - - public void AddEventReference(IEventSymbol @event) - { - AddEventReference(@event.Name, @event.Type, @event, @event.ContainingType); - } - - void AddProjectedType(INamedTypeSymbol type, string projectedTypeOverride = null) - { - currentTypeDeclaration = new TypeDeclaration(type); - - foreach (var member in type.GetMembers()) - { - if (member is IMethodSymbol method && - (method.MethodKind == MethodKind.Ordinary || - method.MethodKind == MethodKind.ExplicitInterfaceImplementation || - method.MethodKind == MethodKind.Constructor)) - { - AddMethodReference(method); - } - else if (member is IPropertySymbol property) - { - AddPropertyReference(property); - } - else if (member is IEventSymbol @event) - { - AddEventReference(@event); - } - else - { - Logger.Log("member not recognized: " + member.Kind + " " + member.Name); - } - } - - typeDefinitionMapping[projectedTypeOverride ?? QualifiedName(type, true)] = currentTypeDeclaration; - } - - void AddMappedType(INamedTypeSymbol type) - { - currentTypeDeclaration = new TypeDeclaration(type); - WriteCustomMappedTypeMembers(type, false); - typeDefinitionMapping[QualifiedName(type, true)] = currentTypeDeclaration; - } - - enum SynthesizedInterfaceType - { - Static, - Factory, - Default - } - - string GetSynthesizedInterfaceName(string className, SynthesizedInterfaceType type) - { - // TODO: handle existing types by appending number suffix - return "I" + className + - type switch - { - SynthesizedInterfaceType.Default => "Class", - SynthesizedInterfaceType.Factory => "Factory", - SynthesizedInterfaceType.Static => "Static", - _ => "", - }; - } - - void AddSynthesizedInterfaces(TypeDeclaration classDeclaration) - { - HashSet classMembersFromInterfaces = new(SymbolEqualityComparer.Default); - INamedTypeSymbol classSymbol = classDeclaration.Node as INamedTypeSymbol; - foreach (var @interface in classSymbol.AllInterfaces) - { - foreach (var interfaceMember in @interface.GetMembers()) - { - var classMember = classSymbol.FindImplementationForInterfaceMember(interfaceMember); - if (classMember == null || !classDeclaration.MethodDefinitions.ContainsKey(classMember)) - { - continue; - } - - classMembersFromInterfaces.Add(classMember); - classDeclaration.ClassInterfaceMemberMapping[classMember] = interfaceMember; - - // Mark class members whose interface declaration has attributes - // so that we can propagate them later. - if (interfaceMember.GetAttributes().Any()) - { - classDeclaration.SymbolsWithAttributes.Add(classMember); - } - } - } - - AddSynthesizedInterface( - classDeclaration, - SynthesizedInterfaceType.Static, - classMembersFromInterfaces); - - AddSynthesizedInterface( - classDeclaration, - SynthesizedInterfaceType.Factory, - classMembersFromInterfaces); - - AddSynthesizedInterface( - classDeclaration, - SynthesizedInterfaceType.Default, - classMembersFromInterfaces); - - // TODO: address overridable and composable interfaces. - } - - void CheckAndMarkSynthesizedInterfaceSymbolForAttributes(ISymbol symbol, TypeDeclaration classDeclaration) - { - // Check the class declaration if the symbol had any attributes marked for it, - // and if so propagate it to the synthesized interface. - if (classDeclaration.SymbolsWithAttributes.Contains(symbol)) - { - currentTypeDeclaration.SymbolsWithAttributes.Add(symbol); - } - } - - void CheckAndMarkSymbolForAttributes(ISymbol symbol) - { - if (symbol.GetAttributes().Any()) - { - currentTypeDeclaration.SymbolsWithAttributes.Add(symbol); - } - } - - void AddSynthesizedInterface( - TypeDeclaration classDeclaration, - SynthesizedInterfaceType interfaceType, - HashSet classMembersFromInterfaces) - { - var typeDeclaration = new TypeDeclaration(); - currentTypeDeclaration = typeDeclaration; - - bool hasTypes = false; - INamedTypeSymbol classSymbol = classDeclaration.Node as INamedTypeSymbol; - - // Each class member results in some form of method definition, - // so using that to our advantage to get public members. - foreach (var classMember in classDeclaration.MethodDefinitions) - { - if (interfaceType == SynthesizedInterfaceType.Factory && - classMember.Key is IMethodSymbol constructorMethod && - constructorMethod.MethodKind == MethodKind.Constructor && - constructorMethod.Parameters.Length != 0) - { - hasTypes = true; - AddFactoryMethod(classSymbol, constructorMethod); - CheckAndMarkSynthesizedInterfaceSymbolForAttributes(classMember.Key, classDeclaration); - } - else if ((interfaceType == SynthesizedInterfaceType.Default && !classMember.Key.IsStatic && - !classMembersFromInterfaces.Contains(classMember.Key)) || - (interfaceType == SynthesizedInterfaceType.Static && classMember.Key.IsStatic)) - { - if (classMember.Key is IMethodSymbol method && method.MethodKind == MethodKind.Ordinary) - { - AddMethodDeclaration(method, true); - } - else if (classMember.Key is IPropertySymbol property) - { - AddPropertyDeclaration(property, true); - } - else if (classMember.Key is IEventSymbol @event) - { - AddEventDeclaration(@event, true); - } - else - { - Logger.Log("member for synthesized interface not recognized: " + classMember.Key.Kind + " " + classMember.Key.Name); - continue; - } - - CheckAndMarkSynthesizedInterfaceSymbolForAttributes(classMember.Key, classDeclaration); - hasTypes = true; - } - } - - TypeAttributes typeAttributes = - TypeAttributes.NotPublic | - TypeAttributes.WindowsRuntime | - TypeAttributes.AutoLayout | - TypeAttributes.AnsiClass | - TypeAttributes.Interface | - TypeAttributes.Abstract; - - if (hasTypes || (interfaceType == SynthesizedInterfaceType.Default && classSymbol.Interfaces.Length == 0)) - { - Logger.Log("writing generated interface " + interfaceType); - var interfaceName = GetSynthesizedInterfaceName(classDeclaration.Node.Name, interfaceType); - var typeDefinitionHandle = AddTypeDefinition( - typeAttributes, - classDeclaration.Node.ContainingNamespace.ToString(), - interfaceName, - default); - typeDeclaration.Handle = typeDefinitionHandle; - - string qualifiedInterfaceName = QualifiedName(classDeclaration.Node.ContainingNamespace.ToString(), interfaceName); - typeDefinitionMapping[qualifiedInterfaceName] = typeDeclaration; - - if (interfaceType == SynthesizedInterfaceType.Default) - { - classDeclaration.DefaultInterface = qualifiedInterfaceName; - var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( - classDeclaration.Handle, - GetTypeReference(classDeclaration.Node.ContainingNamespace.ToString(), interfaceName, assembly)); - classDeclaration.AddInterfaceImpl(classSymbol, interfaceImplHandle); - AddDefaultInterfaceImplAttribute(interfaceImplHandle); - } - - AddDefaultVersionAttribute(typeDefinitionHandle, GetVersion(classSymbol, true)); - AddGuidAttribute(typeDefinitionHandle, interfaceName); - AddExclusiveToAttribute(typeDefinitionHandle, classSymbol.ToString()); - AddOverloadAttributeForInterfaceMethods(typeDeclaration); - - if (interfaceType == SynthesizedInterfaceType.Factory) - { - AddActivatableAttribute(classDeclaration.Handle, (uint)GetVersion(classSymbol, true), qualifiedInterfaceName); - } - else if (interfaceType == SynthesizedInterfaceType.Static) - { - classDeclaration.StaticInterface = qualifiedInterfaceName; - AddStaticAttribute(classDeclaration.Handle, (uint)GetVersion(classSymbol, true), qualifiedInterfaceName); - } - } - } - - private int GetVersion(INamedTypeSymbol type, bool setDefaultIfNotSet = false) - { - var versionAttribute = type.GetAttributes(). - Where(attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "VersionAttribute") == 0); - if (!versionAttribute.Any()) - { - return setDefaultIfNotSet ? Version.Parse(this.version).Major : -1; - } - - uint version = (uint)versionAttribute.First().ConstructorArguments[0].Value; - return (int)version; - } - - void AddType(INamedTypeSymbol type, bool treatAsProjectedType = false) - { - Logger.Log("add type: " + type.ToString()); - bool isProjectedType = type.GetAttributes(). - Any(attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeTypeAttribute") == 0); - var qualifiedName = QualifiedName(type); - if (isProjectedType) - { - AddProjectedType(type); - } - else if (mapper.HasMappingForType(qualifiedName)) - { - var (@namespace, name, assembly, isSystemType, _) = mapper.GetMappedType(qualifiedName).GetMapping(); - if (isSystemType) - { - var projectedType = Model.Compilation.GetTypeByMetadataName(QualifiedName(@namespace, name)); - AddProjectedType(projectedType); - } - else - { - AddMappedType(type); - } - } - else if (treatAsProjectedType) - { - // Prioritize any mapped types before treating an attribute as a projected type. - AddProjectedType(type); - } - else - { - AddComponentType(type); - } - } - - void AddCustomAttributes(TypeDeclaration typeDeclaration, string interfaceName = null) - { - foreach (var node in typeDeclaration.SymbolsWithAttributes) - { - EntityHandle parentHandle; - if (node is INamedTypeSymbol namedType) - { - // Attributes on classes don't propagate to synthesized interfaces. - if (interfaceName != null) - { - continue; - } - - parentHandle = typeDefinitionMapping[namedType.ToString()].Handle; - } - else - { - var typeName = interfaceName ?? node.ContainingType.ToString(); - - if (node is IMethodSymbol method) - { - parentHandle = typeDefinitionMapping[typeName].MethodDefinitions[method][0]; - } - else if (node is IPropertySymbol property) - { - parentHandle = typeDefinitionMapping[typeName].PropertyDefinitions[property]; - } - else if (node is IEventSymbol @event) - { - parentHandle = typeDefinitionMapping[typeName].EventDefinitions[@event]; - } - else - { - Logger.Log("node not recognized " + node.Kind + " name: " + node.Name); - continue; - } - } - - // Add attributes from both the class member declaration and its interface member declaration. - HashSet attributes = new HashSet(node.GetAttributes(), new AttributeDataComparer()); - if (typeDeclaration.ClassInterfaceMemberMapping.ContainsKey(node)) - { - attributes.UnionWith(typeDeclaration.ClassInterfaceMemberMapping[node].GetAttributes()); - } - AddCustomAttributes(attributes, parentHandle); - } - } - - public void FinalizeGeneration() - { - Logger.Log("finalizing"); - var classTypeDeclarations = typeDefinitionMapping.Values - .Where(declaration => declaration.Node is INamedTypeSymbol symbol && symbol.TypeKind == TypeKind.Class) - .ToList(); - - foreach (var classTypeDeclaration in classTypeDeclarations) - { - INamedTypeSymbol classSymbol = classTypeDeclaration.Node as INamedTypeSymbol; - - Logger.Log("finalizing class " + QualifiedName(classSymbol)); - foreach (var implementedInterface in GetInterfaces(classSymbol)) - { - var implementedInterfaceQualifiedNameWithGenerics = QualifiedName(implementedInterface, true); - if (!typeDefinitionMapping.ContainsKey(implementedInterfaceQualifiedNameWithGenerics)) - { - AddType(implementedInterface); - } - - Logger.Log("finalizing interface " + implementedInterfaceQualifiedNameWithGenerics); - var interfaceTypeDeclaration = typeDefinitionMapping[implementedInterfaceQualifiedNameWithGenerics]; - if (mapper.HasMappingForType(QualifiedName(implementedInterface))) - { - Logger.Log("adding MethodImpls for custom mapped interface"); - foreach (var interfaceMember in interfaceTypeDeclaration.MethodReferences) - { - var interfaceMemberMethodDefinitions = interfaceMember.Value; - var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[implementedInterface]; - for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) - { - metadataBuilder.AddMethodImplementation( - classTypeDeclaration.Handle, - classMemberMethodDefinitions[idx], - interfaceMemberMethodDefinitions[idx]); - } - } - } - else - { - Logger.Log("adding MethodImpls for interface"); - foreach (var interfaceMember in interfaceTypeDeclaration.MethodReferences) - { - var classMember = classSymbol.FindImplementationForInterfaceMember(interfaceMember.Key); - if (classTypeDeclaration.MethodDefinitions.ContainsKey(classMember)) - { - var interfaceMemberMethodDefinitions = interfaceMember.Value; - var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[classMember]; - for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) - { - metadataBuilder.AddMethodImplementation( - classTypeDeclaration.Handle, - classMemberMethodDefinitions[idx], - interfaceMemberMethodDefinitions[idx]); - } - - // If method overloaded in interface, overload in class too. - if (interfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) - { - AddOverloadAttribute(classMemberMethodDefinitions.First(), interfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key]); - } - } - } - } - } - - if (classTypeDeclaration.DefaultInterface != null) - { - Logger.Log("finalizing default interface " + classTypeDeclaration.DefaultInterface); - var defaultInterfaceTypeDeclaration = typeDefinitionMapping[classTypeDeclaration.DefaultInterface]; - foreach (var interfaceMember in defaultInterfaceTypeDeclaration.MethodReferences) - { - if (classTypeDeclaration.MethodDefinitions.ContainsKey(interfaceMember.Key)) - { - var interfaceMemberMethodDefinitions = interfaceMember.Value; - var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[interfaceMember.Key]; - for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) - { - metadataBuilder.AddMethodImplementation( - classTypeDeclaration.Handle, - classMemberMethodDefinitions[idx], - interfaceMemberMethodDefinitions[idx]); - } - - // If method overloaded in interface, overload in class too. - if (defaultInterfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) - { - AddOverloadAttribute(classMemberMethodDefinitions.First(), defaultInterfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key]); - } - } - } - } - - if (classTypeDeclaration.StaticInterface != null) - { - Logger.Log("finalizing static interface " + classTypeDeclaration.StaticInterface); - var staticInterfaceTypeDeclaration = typeDefinitionMapping[classTypeDeclaration.StaticInterface]; - foreach (var interfaceMember in staticInterfaceTypeDeclaration.MethodReferences) - { - // If method overloaded in static interface, overload in class too. - if (classTypeDeclaration.MethodDefinitions.ContainsKey(interfaceMember.Key) && - staticInterfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) - { - AddOverloadAttribute( - classTypeDeclaration.MethodDefinitions[interfaceMember.Key].First(), - staticInterfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key] - ); - } - } - } - } - - Logger.Log("adding default version attributes"); - var declarations = typeDefinitionMapping.Values - .Where(declaration => declaration.Node != null) - .ToList(); - foreach (var declaration in declarations) - { - INamedTypeSymbol namedType = declaration.Node as INamedTypeSymbol; - string qualifiedNameWithGenerics = QualifiedName(namedType, true); - if (typeDefinitionMapping[qualifiedNameWithGenerics].Handle != default && GetVersion(namedType) == -1) - { - AddDefaultVersionAttribute(typeDefinitionMapping[qualifiedNameWithGenerics].Handle); - } - } - - Logger.Log("adding custom attributes"); - var typeDeclarationsWithAttributes = typeDefinitionMapping.Values - .Where(declaration => !declaration.IsSynthesizedInterface && declaration.SymbolsWithAttributes.Any()) - .ToList(); - foreach (var typeDeclaration in typeDeclarationsWithAttributes) - { - AddCustomAttributes(typeDeclaration); - - if (typeDeclaration.Node is INamedTypeSymbol symbol && symbol.TypeKind == TypeKind.Class) - { - if (!string.IsNullOrEmpty(typeDeclaration.DefaultInterface)) - { - Logger.Log("adding attributes for default interface " + typeDeclaration.DefaultInterface); - AddCustomAttributes(typeDefinitionMapping[typeDeclaration.DefaultInterface], typeDeclaration.DefaultInterface); - } - - if (!string.IsNullOrEmpty(typeDeclaration.StaticInterface)) - { - Logger.Log("adding attributes for static interface " + typeDeclaration.StaticInterface); - AddCustomAttributes(typeDefinitionMapping[typeDeclaration.StaticInterface], typeDeclaration.StaticInterface); - } - } - } - } - - public void GenerateWinRTExposedClassAttributes(GeneratorExecutionContext context) - { - bool IsWinRTType(ISymbol symbol, TypeMapper mapper) - { - if (!SymbolEqualityComparer.Default.Equals(symbol.ContainingAssembly, context.Compilation.Assembly)) - { - return GeneratorHelper.IsWinRTType(symbol, (symbol, mapper) => IsWinRTType(symbol, mapper), mapper); - } - - if (symbol is INamedTypeSymbol namedType) - { - if (namedType.TypeKind == TypeKind.Interface) - { - // Interfaces which are allowed to be implemented on authored types but - // aren't WinRT interfaces. - return !ImplementedInterfacesWithoutMapping.Contains(QualifiedName(namedType)); - } - - return namedType.SpecialType != SpecialType.System_Object && - namedType.SpecialType != SpecialType.System_Enum && - namedType.SpecialType != SpecialType.System_ValueType && - namedType.SpecialType != SpecialType.System_Delegate && - namedType.SpecialType != SpecialType.System_MulticastDelegate; - } - - // In an authoring component, diagnostics prevents you from using non-WinRT types - // by the time we get to here. - return true; - } - - // If an older CsWinRT version is referenced, it is used to generate the projection. - // The projection generated by it won't be marked partial to generate the attribute on it - // and we also don't support it with the new scenarios without updating CsWinRT package - // So skip generating them. - if (GeneratorHelper.IsOldCsWinRTExe(context)) - { - return; - } - - List vtableAttributesToAdd = new(); - HashSet vtableAttributesToAddOnLookupTable = new(); - - Func isManagedOnlyTypeFunc = GeneratorHelper.IsManagedOnlyType(context.Compilation); - - foreach (var typeDeclaration in typeDefinitionMapping.Values) - { - if (typeDeclaration.IsComponentType && - typeDeclaration.Node is INamedTypeSymbol symbol && - symbol.TypeKind == TypeKind.Class && - !symbol.IsStatic) - { - var vtableAttribute = WinRTAotSourceGenerator.GetVtableAttributeToAdd(symbol, isManagedOnlyTypeFunc, IsWinRTType, mapper, context.Compilation, true, typeDeclaration.DefaultInterface); - if (vtableAttribute != default) - { - vtableAttributesToAdd.Add(vtableAttribute); - } - WinRTAotSourceGenerator.AddVtableAdapterTypeForKnownInterface(symbol, context.Compilation, isManagedOnlyTypeFunc, IsWinRTType, mapper, vtableAttributesToAddOnLookupTable); - } - } - - string escapedAssemblyName = GeneratorHelper.EscapeTypeNameForIdentifier(context.Compilation.AssemblyName); - if (vtableAttributesToAdd.Any() || vtableAttributesToAddOnLookupTable.Any()) - { - WinRTAotSourceGenerator.GenerateCCWForGenericInstantiation( - context.AddSource, - vtableAttributesToAdd.SelectMany(static (vtableAttribute, _) => vtableAttribute.GenericInterfaces). - Union(vtableAttributesToAddOnLookupTable.SelectMany(static (vtableAttribute, _) => vtableAttribute.GenericInterfaces)). - Distinct(). - ToImmutableArray(), - escapedAssemblyName); - } - - if (vtableAttributesToAdd.Any()) - { - WinRTAotSourceGenerator.GenerateVtableAttributes(context.AddSource, vtableAttributesToAdd.ToImmutableArray(), false, escapedAssemblyName); - } - - if (vtableAttributesToAddOnLookupTable.Any()) - { - WinRTAotSourceGenerator.GenerateVtableLookupTable(context.AddSource, (vtableAttributesToAddOnLookupTable.ToImmutableArray(), (new CsWinRTAotOptimizerProperties(true, true, true, false), escapedAssemblyName)), true); - } - } - - public bool IsPublic(ISymbol symbol) - { - // Check that the type has either public accessibility, or is an explicit interface implementation - if (symbol.DeclaredAccessibility == Accessibility.Public || - symbol is IMethodSymbol method && !method.ExplicitInterfaceImplementations.IsDefaultOrEmpty || - symbol is IPropertySymbol property && !property.ExplicitInterfaceImplementations.IsDefaultOrEmpty || - symbol is IEventSymbol @event && !@event.ExplicitInterfaceImplementations.IsDefaultOrEmpty) - { - // If we have a containing type, we also check that it's publicly accessible - return symbol.ContainingType is not { } containingType || containingType.IsPubliclyAccessible(); - } - - return false; - } - - public void GetNamespaceAndTypename(string qualifiedName, out string @namespace, out string typename) - { - var idx = qualifiedName.LastIndexOf('.'); - if (idx == -1) - { - @namespace = ""; - typename = qualifiedName; - } - else - { - @namespace = qualifiedName.Substring(0, idx); - typename = qualifiedName.Substring(idx + 1); - } - } - - public static string QualifiedName(string @namespace, string identifier) - { - if (string.IsNullOrEmpty(@namespace)) - { - return identifier; - } - return string.Join(".", @namespace, identifier); - } - - public static string GetGenericName(ISymbol symbol, bool includeGenerics = false) - { - string name = symbol.Name; - if (symbol is INamedTypeSymbol namedType && namedType.TypeArguments.Length != 0) - { - name += "`" + namedType.TypeArguments.Length; - if (includeGenerics) - { - name += string.Format("<{0}>", string.Join(", ", namedType.TypeArguments)); - } - } - return name; - } - - public static string QualifiedName(ISymbol symbol, bool includeGenerics = false) - { - return QualifiedName(symbol.ContainingNamespace.ToString(), GetGenericName(symbol, includeGenerics)); - } - } -} +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Security.Cryptography; +using System.Text; + +namespace Generator +{ + class Parameter + { + public Symbol Type; + public string Name; + public ParameterAttributes Attributes; + public bool ByRef; + + public Parameter(Symbol type, string name, ParameterAttributes attributes) + : this(type, name, attributes, attributes == ParameterAttributes.Out) + { + } + + public Parameter(Symbol type, string name, ParameterAttributes attributes, bool byRef) + { + Type = type; + Name = name; + Attributes = attributes; + ByRef = byRef; + } + + public Parameter(ITypeSymbol type, string name, ParameterAttributes attributes) + : this(new Symbol(type), name, attributes) + { + } + + public Parameter(EntityHandle type, string name, ParameterAttributes attributes) + : this(new Symbol(type), name, attributes) + { + } + + public Parameter(IParameterSymbol parameterSymbol) + { + // Set out parameter attribute if write only array. + bool isWriteOnlyArray = parameterSymbol.Type is IArrayTypeSymbol && + parameterSymbol.GetAttributes().Where( + attr => string.CompareOrdinal(attr.AttributeClass.ToString(), "System.Runtime.InteropServices.WindowsRuntime.WriteOnlyArrayAttribute") == 0 + ).Count() != 0; + + Type = new Symbol(parameterSymbol.Type); + Name = parameterSymbol.Name; + Attributes = (parameterSymbol.RefKind == RefKind.Out || isWriteOnlyArray) ? ParameterAttributes.Out : ParameterAttributes.In; + ByRef = parameterSymbol.RefKind == RefKind.Out; + } + + public static Parameter[] GetParameters(ParameterListSyntax parameterList, SemanticModel model) + { + int numParameters = parameterList.Parameters.Count; + Parameter[] parameters = new Parameter[numParameters]; + for (int idx = 0; idx < numParameters; idx++) + { + parameters[idx] = new Parameter(model.GetDeclaredSymbol(parameterList.Parameters[idx])); + } + + return parameters; + } + + public static Parameter[] GetParameters(IMethodSymbol method) + { + int numParameters = method.Parameters.Count(); + Parameter[] parameters = new Parameter[numParameters]; + for (int idx = 0; idx < numParameters; idx++) + { + parameters[idx] = new Parameter(method.Parameters[idx]); + } + + return parameters; + } + } + + class Symbol + { + public ITypeSymbol Type; + public EntityHandle Handle; + public int GenericIndex; + public bool IsArray; + + public Symbol(ITypeSymbol type, bool isArray = false) + { + Type = type; + Handle = default; + GenericIndex = -1; + IsArray = isArray; + } + + public Symbol(EntityHandle handle) + { + Type = default; + Handle = handle; + GenericIndex = -1; + } + + public Symbol(int genericIndex, bool isArray) + { + Type = default; + Handle = default; + GenericIndex = genericIndex; + IsArray = isArray; + } + + public bool IsHandle() + { + return Handle != default; + } + + public bool IsGeneric() + { + return GenericIndex != -1; + } + } + + class TypeDeclaration + { + public readonly ISymbol Node; + public TypeDefinitionHandle Handle; + public string DefaultInterface; + public string StaticInterface; + public bool IsSynthesizedInterface; + public bool IsComponentType; + + public Dictionary> MethodDefinitions = new(SymbolEqualityComparer.Default); + public Dictionary> MethodReferences = new(SymbolEqualityComparer.Default); + public Dictionary FieldDefinitions = new(SymbolEqualityComparer.Default); + public Dictionary PropertyDefinitions = new(SymbolEqualityComparer.Default); + public Dictionary EventDefinitions = new(SymbolEqualityComparer.Default); + public Dictionary InterfaceImplDefinitions = new(SymbolEqualityComparer.Default); + public Dictionary> MethodsByName = new Dictionary>(StringComparer.Ordinal); + public Dictionary OverloadedMethods = new(SymbolEqualityComparer.Default); + public List CustomMappedSymbols = new(); + public HashSet SymbolsWithAttributes = new(SymbolEqualityComparer.Default); + public Dictionary ClassInterfaceMemberMapping = new(SymbolEqualityComparer.Default); + + public TypeDeclaration() + : this(null) + { + IsSynthesizedInterface = true; + } + + public TypeDeclaration(ISymbol node, bool isComponentType = false) + { + Node = node; + Handle = default; + IsSynthesizedInterface = false; + IsComponentType = isComponentType; + } + + public override string ToString() + { + return Node.ToString(); + } + + public void AddMethod(ISymbol node, string name, MethodDefinitionHandle handle) + { + if (!MethodDefinitions.ContainsKey(node)) + { + MethodDefinitions[node] = new List(); + MethodReferences[node] = new List(); + } + + if (!MethodsByName.ContainsKey(name)) + { + MethodsByName[name] = new List(); + } + + MethodDefinitions[node].Add(handle); + MethodReferences[node].Add(handle); + MethodsByName[name].Add(node); + } + + public void AddMethodReference(ISymbol node, MemberReferenceHandle handle) + { + if (!MethodReferences.ContainsKey(node)) + { + MethodReferences[node] = new List(); + } + + MethodReferences[node].Add(handle); + } + + public void AddMethodOverload(ISymbol node, string overloadedMethodName) + { + OverloadedMethods[node] = overloadedMethodName; + } + + public List GetMethodDefinitions() + { + return MethodDefinitions.Values.SelectMany(list => list).ToList(); + } + + public List GetMethodReferences() + { + return MethodReferences.Values.SelectMany(list => list).ToList(); + } + + public void AddField(ISymbol node, FieldDefinitionHandle handle) + { + FieldDefinitions[node] = handle; + } + + public List GetFieldDefinitions() + { + return FieldDefinitions.Values.ToList(); + } + + public void AddProperty(ISymbol node, PropertyDefinitionHandle handle) + { + PropertyDefinitions[node] = handle; + } + + public List GetPropertyDefinitions() + { + return PropertyDefinitions.Values.ToList(); + } + + public void AddEvent(ISymbol node, EventDefinitionHandle handle) + { + EventDefinitions[node] = handle; + } + + public List GetEventDefinitions() + { + return EventDefinitions.Values.ToList(); + } + + public void AddInterfaceImpl(ISymbol node, InterfaceImplementationHandle handle) + { + InterfaceImplDefinitions[node] = handle; + } + + } + + class WinRTTypeWriter : CSharpSyntaxWalker + { + internal static readonly List ImplementedInterfacesWithoutMapping = new List() + { + "System.Collections.Generic.ICollection`1", + "System.Collections.Generic.IReadOnlyCollection`1", + "System.Collections.ICollection", + "System.Collections.IEnumerator", + "System.IEquatable`1", + "System.Runtime.InteropServices.ICustomQueryInterface", + "System.Runtime.InteropServices.IDynamicInterfaceCastable", + "WinRT.IWinRTObject" + }; + + public SemanticModel Model; + + private readonly string assembly; + private readonly string version; + + private readonly Dictionary typeReferenceMapping; + private readonly Dictionary assemblyReferenceMapping; + private readonly MetadataBuilder metadataBuilder; + private readonly TypeMapper mapper; + private readonly Dictionary typeDefinitionMapping; + private TypeDeclaration currentTypeDeclaration; + + private Logger Logger { get; } + + public WinRTTypeWriter( + string assembly, + string version, + MetadataBuilder metadataBuilder, + Logger logger, + TypeMapper mapper) + { + this.assembly = assembly; + this.version = version; + this.metadataBuilder = metadataBuilder; + Logger = logger; + this.mapper = mapper; + typeReferenceMapping = new Dictionary(StringComparer.Ordinal); + assemblyReferenceMapping = new Dictionary(StringComparer.Ordinal); + typeDefinitionMapping = new Dictionary(StringComparer.Ordinal); + + CreteAssembly(); + } + + private void CreteAssembly() + { + Logger.Log("Generating assembly " + assembly + " version " + version); + metadataBuilder.AddAssembly( + metadataBuilder.GetOrAddString(assembly), + new Version(version), + default, + default, + AssemblyFlags.WindowsRuntime, + AssemblyHashAlgorithm.Sha1); + + var moduleDefinition = metadataBuilder.AddModule( + 0, + metadataBuilder.GetOrAddString(assembly + ".winmd"), + metadataBuilder.GetOrAddGuid(Guid.NewGuid()), + default, + default); + assemblyReferenceMapping[assembly] = moduleDefinition; + + metadataBuilder.AddTypeDefinition( + default, + default, + metadataBuilder.GetOrAddString(""), + default, + MetadataTokens.FieldDefinitionHandle(1), + MetadataTokens.MethodDefinitionHandle(1)); + } + + private bool IsEncodableAsSpecialType(SpecialType specialType) + { + return specialType != SpecialType.None && specialType <= SpecialType.System_Array; + } + + private void EncodeSpecialType(SpecialType specialType, SignatureTypeEncoder typeEncoder) + { + switch (specialType) + { + case SpecialType.System_Boolean: + typeEncoder.Boolean(); + break; + case SpecialType.System_Byte: + typeEncoder.Byte(); + break; + case SpecialType.System_Int16: + typeEncoder.Int16(); + break; + case SpecialType.System_Int32: + typeEncoder.Int32(); + break; + case SpecialType.System_Int64: + typeEncoder.Int64(); + break; + case SpecialType.System_UInt16: + typeEncoder.UInt16(); + break; + case SpecialType.System_UInt32: + typeEncoder.UInt32(); + break; + case SpecialType.System_UInt64: + typeEncoder.UInt64(); + break; + case SpecialType.System_Single: + typeEncoder.Single(); + break; + case SpecialType.System_Double: + typeEncoder.Double(); + break; + case SpecialType.System_Char: + typeEncoder.Char(); + break; + case SpecialType.System_String: + typeEncoder.String(); + break; + case SpecialType.System_Object: + typeEncoder.Object(); + break; + case SpecialType.System_IntPtr: + typeEncoder.IntPtr(); + break; + default: + Logger.Log("TODO special type: " + specialType); + break; + } + + // TODO: handle C# interface mappings for special types + } + + private BlobHandle GetStrongNameKey(string assembly) + { + if (string.CompareOrdinal(assembly, "mscorlib") == 0) + { + byte[] mscorlibStrongName = { 0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89 }; + return metadataBuilder.GetOrAddBlob(mscorlibStrongName); + } + + return default; + } + + private EntityHandle GetTypeReference(string @namespace, string name, string assembly) + { + string fullname = QualifiedName(@namespace, name); + if (typeReferenceMapping.ContainsKey(fullname)) + { + return typeReferenceMapping[fullname]; + } + + if (!assemblyReferenceMapping.ContainsKey(assembly)) + { + EntityHandle assemblyReference = metadataBuilder.AddAssemblyReference( + metadataBuilder.GetOrAddString(assembly), + new Version(0xff, 0xff, 0xff, 0xff), + default, + GetStrongNameKey(assembly), + string.CompareOrdinal(assembly, "mscorlib") == 0 ? default : AssemblyFlags.WindowsRuntime, + default); + assemblyReferenceMapping[assembly] = assemblyReference; + } + + var typeRef = metadataBuilder.AddTypeReference( + assemblyReferenceMapping[assembly], + metadataBuilder.GetOrAddString(@namespace), + metadataBuilder.GetOrAddString(name)); + typeReferenceMapping[fullname] = typeRef; + return typeRef; + } + + public string GetAssemblyForWinRTType(ISymbol type) + { + var winrtTypeAttribute = type.GetAttributes(). + Where(attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeTypeAttribute") == 0); + if (winrtTypeAttribute.Any()) + { + return (string)winrtTypeAttribute.First().ConstructorArguments[0].Value; + } + + return null; + } + + private EntityHandle GetTypeReference(ISymbol symbol) + { + string @namespace = symbol.ContainingNamespace.ToString(); + string name = GetGenericName(symbol); + + string fullType = QualifiedName(@namespace, name); + var assembly = GetAssemblyForWinRTType(symbol); + if (assembly == null) + { + if (mapper.HasMappingForType(fullType)) + { + (@namespace, name, assembly, _, _) = mapper.GetMappedType(fullType).GetMapping(currentTypeDeclaration.Node); + Logger.Log("custom mapping " + fullType + " to " + QualifiedName(@namespace, name) + " from " + assembly); + } + else + { + assembly = symbol.ContainingAssembly.Name; + } + } + + return GetTypeReference(@namespace, name, assembly); + } + + private EntityHandle GetTypeSpecification(INamedTypeSymbol symbol) + { + if (symbol.IsGenericType) + { + Logger.Log("Adding TypeSpec for " + symbol.ToString()); + var typeSpecSignature = new BlobBuilder(); + var genericType = new BlobEncoder(typeSpecSignature) + .TypeSpecificationSignature() + .GenericInstantiation(GetTypeReference(symbol), symbol.TypeArguments.Length, false); + foreach (var typeArgument in symbol.TypeArguments) + { + EncodeSymbol(new Symbol(typeArgument), genericType.AddArgument()); + } + + return metadataBuilder.AddTypeSpecification(metadataBuilder.GetOrAddBlob(typeSpecSignature)); + } + else + { + return GetTypeReference(symbol); + } + } + + private void EncodeSymbol(Symbol symbol, SignatureTypeEncoder typeEncoder) + { + if (symbol.IsHandle()) + { + typeEncoder.Type(symbol.Handle, false); + } + else if (symbol.IsGeneric()) + { + if (symbol.IsArray) + { + typeEncoder.SZArray().GenericTypeParameter(symbol.GenericIndex); + } + else + { + typeEncoder.GenericTypeParameter(symbol.GenericIndex); + } + } + else if (symbol.IsArray) + { + EncodeSymbol(new Symbol(symbol.Type), typeEncoder.SZArray()); + } + else if (symbol.Type is IArrayTypeSymbol arrayType) + { + EncodeSymbol(new Symbol(arrayType.ElementType), typeEncoder.SZArray()); + } + else if (symbol.Type is INamedTypeSymbol namedType && namedType.TypeArguments.Length != 0) + { + var genericType = typeEncoder.GenericInstantiation(GetTypeReference(symbol.Type), namedType.TypeArguments.Length, false); + int parameterIndex = 0; + foreach (var typeArgument in namedType.TypeArguments) + { + if (namedType.IsUnboundGenericType) + { + genericType.AddArgument().GenericTypeParameter(parameterIndex); + } + else + { + EncodeSymbol(new Symbol(typeArgument), genericType.AddArgument()); + } + parameterIndex++; + } + } + else if (IsEncodableAsSpecialType(symbol.Type.SpecialType)) + { + EncodeSpecialType(symbol.Type.SpecialType, typeEncoder); + } + else + { + bool isValueType = symbol.Type.TypeKind == TypeKind.Enum || symbol.Type.TypeKind == TypeKind.Struct; + if (mapper.HasMappingForType(QualifiedName(symbol.Type))) + { + (_, _, _, _, isValueType) = mapper.GetMappedType(QualifiedName(symbol.Type)).GetMapping(currentTypeDeclaration.Node); + } + typeEncoder.Type(GetTypeReference(symbol.Type), isValueType); + } + } + + private void EncodeReturnType(Symbol symbol, ReturnTypeEncoder returnTypeEncoder) + { + if (symbol == null) + { + returnTypeEncoder.Void(); + } + else if (symbol.IsHandle() || symbol.IsGeneric() || !IsEncodableAsSpecialType(symbol.Type.SpecialType)) + { + EncodeSymbol(symbol, returnTypeEncoder.Type()); + } + else if (symbol.Type.SpecialType == SpecialType.System_Void) + { + returnTypeEncoder.Void(); + } + else + { + EncodeSpecialType(symbol.Type.SpecialType, returnTypeEncoder.Type()); + } + } + + private void EncodeParameters(Parameter[] parameters, ParametersEncoder parametersEncoder) + { + foreach (var parameter in parameters) + { + var parameterType = parameter.Type; + var parameterTypeEncoder = parametersEncoder.AddParameter(); + + if (!parameterType.IsHandle() && !parameterType.IsGeneric() && IsEncodableAsSpecialType(parameterType.Type.SpecialType)) + { + EncodeSpecialType(parameterType.Type.SpecialType, parameterTypeEncoder.Type(parameter.ByRef)); + } + else + { + EncodeSymbol(parameterType, parameterTypeEncoder.Type(parameter.ByRef)); + } + } + } + + public MethodDefinitionHandle AddMethodDefinition( + string name, + Parameter[] parameters, + Symbol returnSymbol, + bool isStatic, + bool isInterfaceParent, + bool isSpecialMethod = false, + bool isPublic = true, + bool isOverridable = false) + { + var methodSignature = new BlobBuilder(); + new BlobEncoder(methodSignature) + .MethodSignature( + SignatureCallingConvention.Default, + 0, + !isStatic) + .Parameters( + parameters.Length, + returnType => EncodeReturnType(returnSymbol, returnType), + parametersEncoder => EncodeParameters(parameters, parametersEncoder) + ); + + List parameterHandles = new List(); + for (int idx = 0; idx < parameters.Length; idx++) + { + parameterHandles.Add(metadataBuilder.AddParameter( + parameters[idx].Attributes, + metadataBuilder.GetOrAddString(parameters[idx].Name), + idx + 1)); + } + + var methodAttributes = + (isPublic ? MethodAttributes.Public : MethodAttributes.Private) | + MethodAttributes.HideBySig; + + var methodImplAttributes = MethodImplAttributes.Managed; + + if (isInterfaceParent) + { + methodAttributes |= MethodAttributes.Abstract; + } + else + { + methodImplAttributes |= MethodImplAttributes.Runtime; + } + + if (isSpecialMethod && string.CompareOrdinal(name, ".ctor") == 0) + { + methodAttributes |= MethodAttributes.RTSpecialName; + } + else if (isStatic) + { + methodAttributes |= MethodAttributes.Static; + } + else + { + methodAttributes |= + MethodAttributes.Virtual | + MethodAttributes.NewSlot; + + if (!isOverridable && !isInterfaceParent) + { + methodAttributes |= MethodAttributes.Final; + } + } + + if (isSpecialMethod) + { + methodAttributes |= MethodAttributes.SpecialName; + } + + var methodDefinitionHandle = metadataBuilder.AddMethodDefinition( + methodAttributes, + methodImplAttributes, + metadataBuilder.GetOrAddString(name), + metadataBuilder.GetOrAddBlob(methodSignature), + -1, + parameterHandles.Count == 0 ? + MetadataTokens.ParameterHandle(metadataBuilder.GetRowCount(TableIndex.Param) + 1) : + parameterHandles[0]); + return methodDefinitionHandle; + } + + public void AddFieldDeclaration(IFieldSymbol field, bool isEnum) + { + Logger.Log("defining field " + field.Name + " with type " + field.Type.ToString()); + + var fieldSignature = new BlobBuilder(); + var encoder = new BlobEncoder(fieldSignature); + EncodeSymbol(new Symbol(field.Type), encoder.FieldSignature()); + + var fieldAttributes = FieldAttributes.Public; + if (isEnum) + { + fieldAttributes |= + FieldAttributes.Static | + FieldAttributes.Literal | + FieldAttributes.HasDefault; + } + + var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( + fieldAttributes, + metadataBuilder.GetOrAddString(field.Name), + metadataBuilder.GetOrAddBlob(fieldSignature)); + currentTypeDeclaration.AddField(field, fieldDefinitionHandle); + + if (isEnum && field.HasConstantValue) + { + metadataBuilder.AddConstant(fieldDefinitionHandle, field.ConstantValue); + } + } + + public void AddPropertyDefinition( + string propertyName, + Symbol type, + ISymbol symbol, + bool isStatic, + bool hasSetMethod, + bool isInterfaceParent, + bool isPublic = true) + { + Logger.Log("defining property " + propertyName); + GetNamespaceAndTypename(propertyName, out var @namespace, out var typename); + + var propertySignature = new BlobBuilder(); + new BlobEncoder(propertySignature) + .PropertySignature(!isStatic) + .Parameters( + 0, + returnType => EncodeReturnType(type, returnType), + parameters => { } + ); + + var propertyDefinitonHandle = metadataBuilder.AddProperty( + PropertyAttributes.None, + metadataBuilder.GetOrAddString(propertyName), + metadataBuilder.GetOrAddBlob(propertySignature)); + currentTypeDeclaration.AddProperty(symbol, propertyDefinitonHandle); + + if (hasSetMethod) + { + string setMethodName = QualifiedName(@namespace, "put_" + typename); + var setMethod = AddMethodDefinition( + setMethodName, + new Parameter[] { new Parameter(type, "value", ParameterAttributes.In) }, + null, + !isInterfaceParent && isStatic, + isInterfaceParent, + true, + isPublic); + currentTypeDeclaration.AddMethod(symbol, setMethodName, setMethod); + + metadataBuilder.AddMethodSemantics( + propertyDefinitonHandle, + MethodSemanticsAttributes.Setter, + setMethod); + } + + string getMethodName = QualifiedName(@namespace, "get_" + typename); + var getMethod = AddMethodDefinition( + getMethodName, + new Parameter[0], + type, + !isInterfaceParent && isStatic, + isInterfaceParent, + true, + isPublic); + currentTypeDeclaration.AddMethod(symbol, getMethodName, getMethod); + + metadataBuilder.AddMethodSemantics( + propertyDefinitonHandle, + MethodSemanticsAttributes.Getter, + getMethod); + } + + public void AddPropertyDeclaration(IPropertySymbol property, bool isInterfaceParent) + { + AddPropertyDefinition( + property.Name, + new Symbol(property.Type), + property, + property.IsStatic, + property.SetMethod != null && + (property.SetMethod.DeclaredAccessibility == Accessibility.Public || + !property.SetMethod.ExplicitInterfaceImplementations.IsDefaultOrEmpty), + isInterfaceParent, + property.ExplicitInterfaceImplementations.IsDefaultOrEmpty); + } + + private TypeDefinitionHandle AddTypeDefinition( + TypeAttributes typeAttributes, + string @namespace, + string identifier, + EntityHandle baseType) + { + var fieldDefinitions = currentTypeDeclaration.GetFieldDefinitions(); + var methodDefinitions = currentTypeDeclaration.GetMethodDefinitions(); + + var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( + typeAttributes, + metadataBuilder.GetOrAddString(@namespace), + metadataBuilder.GetOrAddString(identifier), + baseType, + fieldDefinitions.Count == 0 ? + MetadataTokens.FieldDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.Field) + 1) : + fieldDefinitions[0], + methodDefinitions.Count == 0 ? + MetadataTokens.MethodDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.MethodDef) + 1) : + methodDefinitions[0] + ); + + var propertyDefinitions = currentTypeDeclaration.GetPropertyDefinitions(); + if (propertyDefinitions.Count != 0) + { + metadataBuilder.AddPropertyMap( + typeDefinitionHandle, + propertyDefinitions[0]); + } + + var eventDefinitions = currentTypeDeclaration.GetEventDefinitions(); + if (eventDefinitions.Count != 0) + { + metadataBuilder.AddEventMap( + typeDefinitionHandle, + eventDefinitions[0]); + } + + return typeDefinitionHandle; + } + + private void ProcessCustomMappedInterfaces(INamedTypeSymbol classSymbol) + { + Logger.Log("writing custom mapped interfaces for " + QualifiedName(classSymbol)); + Dictionary isPublicImplementation = new(SymbolEqualityComparer.Default); + + // Mark custom mapped interface members for removal later. + // Note we want to also mark members from interfaces without mappings. + foreach (var implementedInterface in GetInterfaces(classSymbol, true). + Where(symbol => mapper.HasMappingForType(QualifiedName(symbol)) || + ImplementedInterfacesWithoutMapping.Contains(QualifiedName(symbol)))) + { + bool isPubliclyImplemented = false; + Logger.Log("custom mapped interface: " + QualifiedName(implementedInterface, true)); + foreach (var interfaceMember in implementedInterface.GetMembers()) + { + var classMember = classSymbol.FindImplementationForInterfaceMember(interfaceMember); + currentTypeDeclaration.CustomMappedSymbols.Add(classMember); + + // For custom mapped interfaces, we don't have 1 to 1 mapping of members between the mapped from + // and mapped to interface and due to that we need to decide if the mapped inteface as a whole + // is public or not (explicitly implemented). Due to that, as long as one member is not + // explicitly implemented (i.e accessible via the class), we treat the entire mapped interface + // also as accessible via the class. + isPubliclyImplemented |= (classMember.DeclaredAccessibility == Accessibility.Public); + } + isPublicImplementation[implementedInterface] = isPubliclyImplemented; + } + + foreach (var implementedInterface in GetInterfaces(classSymbol) + .Where(symbol => mapper.HasMappingForType(QualifiedName(symbol)))) + { + WriteCustomMappedTypeMembers(implementedInterface, true, isPublicImplementation[implementedInterface]); + } + } + + INamedTypeSymbol GetTypeByMetadataName(string metadataName) + { + var namedType = Model.Compilation.GetTypeByMetadataName(metadataName); + if (namedType != null) + { + return namedType; + } + + // Model.Compilation.GetTypeByMetadataName doesn't return a type if there is multiple references with the same type. + // So as a fallback, go through all the references and check each one filtering to public ones. + var types = Model.Compilation.References + .Select(Model.Compilation.GetAssemblyOrModuleSymbol) + .OfType() + .Select(assemblySymbol => assemblySymbol.GetTypeByMetadataName(metadataName)) + .Where(type => type != null && type.DeclaredAccessibility == Accessibility.Public); + return types.FirstOrDefault(); + } + + // Convert the entire type name including the generic types to WinMD format. + private string GetMappedQualifiedTypeName(ITypeSymbol symbol) + { + string qualifiedName = QualifiedName(symbol); + if (mapper.HasMappingForType(qualifiedName)) + { + var (@namespace, mappedTypeName, _, _, _) = mapper.GetMappedType(qualifiedName).GetMapping(currentTypeDeclaration.Node); + qualifiedName = QualifiedName(@namespace, mappedTypeName); + if (symbol is INamedTypeSymbol namedType && namedType.TypeArguments.Length > 0) + { + return string.Format("{0}<{1}>", qualifiedName, string.Join(", ", namedType.TypeArguments.Select(type => GetMappedQualifiedTypeName(type)))); + } + } + else if ((string.CompareOrdinal(symbol.ContainingNamespace.ToString(), "System") == 0 && + symbol.IsValueType) || string.CompareOrdinal(qualifiedName, "System.String") == 0) + { + // WinRT fundamental types + return symbol.Name; + } + + return qualifiedName; + } + + private void WriteCustomMappedTypeMembers(INamedTypeSymbol symbol, bool isDefinition, bool isPublic = true) + { + var (_, mappedTypeName, _, _, _) = mapper.GetMappedType(QualifiedName(symbol)).GetMapping(currentTypeDeclaration.Node); + string qualifiedName = GetMappedQualifiedTypeName(symbol); + + Logger.Log("writing custom mapped type members for " + mappedTypeName + " public: " + isPublic + " qualified name: " + qualifiedName); + void AddMethod(string name, Parameter[] parameters, Symbol returnType) + { + parameters ??= new Parameter[0]; + if (isDefinition) + { + var methodName = isPublic ? name : QualifiedName(qualifiedName, name); + var methodDefinitionHandle = AddMethodDefinition(methodName, parameters, returnType, false, false, false, isPublic); + currentTypeDeclaration.AddMethod(symbol, methodName, methodDefinitionHandle); + } + else + { + var memberReferenceHandle = AddMethodReference(name, parameters, returnType, symbol, false); + currentTypeDeclaration.AddMethodReference(symbol, memberReferenceHandle); + } + } + + void AddProperty(string name, Symbol type, bool setProperty) + { + if (isDefinition) + { + var propertyName = isPublic ? name : QualifiedName(qualifiedName, name); + AddPropertyDefinition(propertyName, type, symbol, false, setProperty, false, isPublic); + } + else + { + AddPropertyReference(name, type, symbol, symbol, setProperty); + } + } + + void AddEvent(string name, Symbol eventType) + { + if (isDefinition) + { + var eventName = isPublic ? name : QualifiedName(qualifiedName, name); + AddEventDeclaration(eventName, eventType.Type, symbol, false, false, isPublic); + } + else + { + AddEventReference(name, eventType.Type, symbol, symbol); + } + } + + Symbol GetType(string type, bool isGeneric = false, int genericIndex = -1, bool isArray = false, ITypeSymbol[] genericTypes = null) + { + if (string.IsNullOrEmpty(type) && isGeneric) + { + return isDefinition ? new Symbol(symbol.TypeArguments[genericIndex], isArray) : new Symbol(genericIndex, isArray); + } + + var namedTypeSymbol = GetTypeByMetadataName(type); + if (!isGeneric) + { + return new Symbol(namedTypeSymbol, isArray); + } + + if (isDefinition) + { + var typeArguments = genericTypes ?? ((genericIndex == -1) ? + symbol.TypeArguments.ToArray() : new ITypeSymbol[] { symbol.TypeArguments[genericIndex] }); + return new Symbol(namedTypeSymbol.Construct(typeArguments), isArray); + } + else + { + return new Symbol(namedTypeSymbol.ConstructUnboundGenericType(), isArray); + } + } + + if (string.CompareOrdinal(mappedTypeName, "IClosable") == 0) + { + AddMethod("Close", null, null); + } + else if (string.CompareOrdinal(mappedTypeName, "IIterable`1") == 0) + { + AddMethod("First", null, GetType("System.Collections.Generic.IEnumerator`1", true)); + } + else if (string.CompareOrdinal(mappedTypeName, "IMap`2") == 0) + { + AddMethod("Clear", null, null); + AddMethod("GetView", null, GetType("System.Collections.Generic.IReadOnlyDictionary`2", true)); + AddMethod( + "HasKey", + new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, + GetType("System.Boolean") + ); + AddMethod( + "Insert", + new[] { + new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In), + new Parameter(GetType(null, true, 1), "value", ParameterAttributes.In) + }, + GetType("System.Boolean") + ); + AddMethod( + "Lookup", + new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, + GetType(null, true, 1) + ); + AddMethod( + "Remove", + new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, + null + ); + AddProperty("Size", GetType("System.UInt32"), false); + } + else if (string.CompareOrdinal(mappedTypeName, "IMapView`2") == 0) + { + AddMethod( + "HasKey", + new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, + GetType("System.Boolean") + ); + AddMethod( + "Lookup", + new[] { new Parameter(GetType(null, true, 0), "key", ParameterAttributes.In) }, + GetType(null, true, 1) + ); + AddMethod( + "Split", + new[] { + new Parameter(GetType("System.Collections.Generic.IReadOnlyDictionary`2", true), "first", ParameterAttributes.Out), + new Parameter(GetType("System.Collections.Generic.IReadOnlyDictionary`2", true), "second", ParameterAttributes.Out) + }, + null + ); + AddProperty("Size", GetType("System.UInt32"), false); + } + else if (string.CompareOrdinal(mappedTypeName, "IIterator`1") == 0) + { + // make array + AddMethod( + "GetMany", + new[] { new Parameter(GetType(null, true, 0, true), "items", ParameterAttributes.In, false) }, + GetType("System.UInt32") + ); + AddMethod( + "MoveNext", + null, + GetType("System.Boolean") + ); + AddProperty("Current", GetType(null, true, 0), false); + AddProperty("HasCurrent", GetType("System.Boolean"), false); + } + else if (string.CompareOrdinal(mappedTypeName, "IVector`1") == 0) + { + AddMethod( + "Append", + new[] { new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In) }, + null + ); + AddMethod("Clear", null, null); + AddMethod( + "GetAt", + new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, + GetType(null, true, 0) + ); + AddMethod( + "GetMany", + new[] { + new Parameter(GetType("System.UInt32"), "startIndex", ParameterAttributes.In), + new Parameter(GetType(null, true, 0, true), "items", ParameterAttributes.In) + }, + GetType("System.UInt32") + ); + AddMethod("GetView", null, GetType("System.Collections.Generic.IReadOnlyList`1", true)); + AddMethod( + "IndexOf", + new[] { + new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In), + new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.Out) + }, + GetType("System.Boolean") + ); + AddMethod( + "InsertAt", + new[] { + new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In), + new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In), + }, + null + ); + AddMethod( + "RemoveAt", + new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, + null + ); + AddMethod("RemoveAtEnd", null, null); + AddMethod( + "ReplaceAll", + new[] { + new Parameter(GetType(null, true, 0, true), "items", ParameterAttributes.In) + }, + null + ); + AddMethod( + "SetAt", + new[] { + new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In), + new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In), + }, + null + ); + AddProperty("Size", GetType("System.UInt32"), false); + } + else if (string.CompareOrdinal(mappedTypeName, "IVectorView`1") == 0) + { + AddMethod( + "GetAt", + new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, + GetType(null, true, 0) + ); + AddMethod( + "GetMany", + new[] { + new Parameter(GetType("System.UInt32"), "startIndex", ParameterAttributes.In), + new Parameter(GetType(null, true, 0, true), "items", ParameterAttributes.In) + }, + GetType("System.UInt32") + ); + AddMethod( + "IndexOf", + new[] { + new Parameter(GetType(null, true, 0), "value", ParameterAttributes.In), + new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.Out) + }, + GetType("System.Boolean") + ); + AddProperty("Size", GetType("System.UInt32"), false); + } + else if (string.CompareOrdinal(mappedTypeName, "IXamlServiceProvider") == 0) + { + AddMethod( + "GetService", + new[] { new Parameter(GetType("System.Type"), "type", ParameterAttributes.In) }, + GetType("System.Object") + ); + } + else if (string.CompareOrdinal(mappedTypeName, "INotifyDataErrorInfo") == 0) + { + AddProperty("HasErrors", GetType("System.Boolean"), false); + AddEvent( + "ErrorsChanged", + GetType("System.EventHandler`1", true, -1, false, new[] { GetType("System.ComponentModel.DataErrorsChangedEventArgs").Type })); + AddMethod( + "GetErrors", + new[] { new Parameter(GetType("System.String"), "propertyName", ParameterAttributes.In) }, + GetType("System.Collections.Generic.IEnumerable`1", true, -1, false, new[] { GetType("System.Object").Type }) + ); + } + else if (string.CompareOrdinal(mappedTypeName, "INotifyPropertyChanged") == 0) + { + AddEvent("PropertyChanged", GetType("System.ComponentModel.PropertyChangedEventHandler")); + } + else if (string.CompareOrdinal(mappedTypeName, "ICommand") == 0) + { + AddEvent( + "CanExecuteChanged", + GetType("System.EventHandler`1", true, -1, false, new[] { GetType("System.Object").Type })); + AddMethod( + "CanExecute", + new[] { new Parameter(GetType("System.Object"), "parameter", ParameterAttributes.In) }, + GetType("System.Boolean") + ); + AddMethod( + "Execute", + new[] { new Parameter(GetType("System.Object"), "parameter", ParameterAttributes.In) }, + null + ); + } + else if (string.CompareOrdinal(mappedTypeName, "IBindableIterable") == 0) + { + AddMethod("First", null, GetType("Microsoft.UI.Xaml.Interop.IBindableIterator")); + } + else if (string.CompareOrdinal(mappedTypeName, "IBindableVector") == 0) + { + AddMethod( + "Append", + new[] { new Parameter(GetType("System.Object"), "value", ParameterAttributes.In) }, + null + ); + AddMethod("Clear", null, null); + AddMethod( + "GetAt", + new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, + GetType("System.Object") + ); + AddMethod("GetView", null, GetType("Microsoft.UI.Xaml.Interop.IBindableVectorView")); + AddMethod( + "IndexOf", + new[] { + new Parameter(GetType("System.Object"), "value", ParameterAttributes.In), + new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.Out) + }, + GetType("System.Boolean") + ); + AddMethod( + "InsertAt", + new[] { + new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In), + new Parameter(GetType("System.Object"), "value", ParameterAttributes.In), + }, + null + ); + AddMethod( + "RemoveAt", + new[] { new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In) }, + null + ); + AddMethod("RemoveAtEnd", null, null); + AddMethod( + "SetAt", + new[] { + new Parameter(GetType("System.UInt32"), "index", ParameterAttributes.In), + new Parameter(GetType("System.Object"), "value", ParameterAttributes.In), + }, + null + ); + AddProperty("Size", GetType("System.UInt32"), false); + } + else if (string.CompareOrdinal(mappedTypeName, "INotifyCollectionChanged") == 0) + { + AddEvent("CollectionChanged", GetType("System.Collections.Specialized.NotifyCollectionChangedEventHandler")); + } + } + + private IEnumerable GetInterfaces(INamedTypeSymbol symbol, bool includeInterfacesWithoutMappings = false) + { + HashSet interfaces = new(SymbolEqualityComparer.Default); + + // Gather all interfaces that are publicly accessible. We specifically need to exclude interfaces + // that are not public, as eg. those might be used for additional cloaked WinRT/COM interfaces. + // Ignoring them here makes sure that they're not processed to be part of the .winmd file. + void GatherPubliclyAccessibleInterfaces(ITypeSymbol symbol) + { + foreach (var @interface in symbol.Interfaces) + { + if (@interface.IsPubliclyAccessible()) + { + _ = interfaces.Add(@interface); + } + + // We're not using AllInterfaces on purpose: we only want to gather all interfaces but not + // from the base type. That's handled below to skip types that are already WinRT projections. + foreach (var @interface2 in @interface.AllInterfaces) + { + if (@interface2.IsPubliclyAccessible()) + { + _ = interfaces.Add(@interface2); + } + } + } + } + + GatherPubliclyAccessibleInterfaces(symbol); + + var baseType = symbol.BaseType; + while (baseType != null && !GeneratorHelper.IsWinRTType(baseType, mapper)) + { + GatherPubliclyAccessibleInterfaces(baseType); + + baseType = baseType.BaseType; + } + + // If the generic enumerable is implemented, don't implement the non generic one to prevent issues + // with the interface members being implemented multiple times. + if (!includeInterfacesWithoutMappings && + interfaces.Any(@interface => string.CompareOrdinal(QualifiedName(@interface), "System.Collections.Generic.IEnumerable`1") == 0)) + { + interfaces.Remove(GetTypeByMetadataName("System.Collections.IEnumerable")); + } + + return interfaces.Where(@interface => + includeInterfacesWithoutMappings || + !ImplementedInterfacesWithoutMapping.Contains(QualifiedName(@interface))) + .OrderBy(implementedInterface => implementedInterface.ToString()); + } + + public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) + { + AddComponentType(Model.GetDeclaredSymbol(node), () => base.VisitInterfaceDeclaration(node)); + } + + public override void VisitClassDeclaration(ClassDeclarationSyntax node) + { + AddComponentType(Model.GetDeclaredSymbol(node), () => base.VisitClassDeclaration(node)); + } + + public override void VisitStructDeclaration(StructDeclarationSyntax node) + { + AddComponentType(Model.GetDeclaredSymbol(node), () => base.VisitStructDeclaration(node)); + } + + private void EncodeTypedConstant(TypedConstant constant, LiteralEncoder encoder) + { + Logger.Log("typed constant kind: " + constant.Kind); + Logger.Log("typed constant type: " + constant.Type); + Logger.Log("typed constant value: " + constant.Value); + + switch (constant.Kind) + { + case TypedConstantKind.Primitive: + encoder.Scalar().Constant(constant.Value); + break; + case TypedConstantKind.Enum: + encoder.Scalar().Constant(constant.Value); + + // This looks more correct, but the code above matches what the C# compiler produces. + // Eg. win32metadata does the same (see 'MetadataUtils.EncodeHelpers' in https://github.com/microsoft/win32metadata). + // encoder.TaggedScalar( + // type => type.Enum(constant.Type.ToString()), + // scalar => scalar.Constant(constant.Value) + // ); + + break; + case TypedConstantKind.Type: + encoder.Scalar().SystemType(constant.Value.ToString()); + break; + case TypedConstantKind.Array: + { + LiteralsEncoder arrayEncoder = encoder.Vector().Count(constant.Values.Length); + foreach (var arrayConstant in constant.Values) + { + EncodeTypedConstant(arrayConstant, arrayEncoder.AddLiteral()); + } + break; + } + } + } + + private void EncodeFixedArguments(IList arguments, FixedArgumentsEncoder argumentsEncoder) + { + foreach (var argument in arguments) + { + EncodeTypedConstant(argument, argumentsEncoder.AddArgument()); + } + } + + private void EncodeCustomElementType(ITypeSymbol type, CustomAttributeElementTypeEncoder typeEncoder) + { + switch (type.SpecialType) + { + case SpecialType.System_Boolean: + typeEncoder.Boolean(); + break; + case SpecialType.System_Byte: + typeEncoder.Byte(); + break; + case SpecialType.System_Int16: + typeEncoder.Int16(); + break; + case SpecialType.System_Int32: + typeEncoder.Int32(); + break; + case SpecialType.System_Int64: + typeEncoder.Int64(); + break; + case SpecialType.System_UInt16: + typeEncoder.UInt16(); + break; + case SpecialType.System_UInt32: + typeEncoder.UInt32(); + break; + case SpecialType.System_UInt64: + typeEncoder.UInt64(); + break; + case SpecialType.System_Single: + typeEncoder.Single(); + break; + case SpecialType.System_Double: + typeEncoder.Double(); + break; + case SpecialType.System_Char: + typeEncoder.Char(); + break; + case SpecialType.System_String: + typeEncoder.String(); + break; + case SpecialType.System_Enum: + typeEncoder.Enum(type.ToString()); + break; + case SpecialType.System_SByte: + typeEncoder.SByte(); + break; + default: + Logger.Log("TODO special type: " + type.SpecialType); + break; + } + } + + private void EncodeNamedArgumentType(ITypeSymbol type, NamedArgumentTypeEncoder encoder) + { + Logger.Log("encoding named type"); + if (type.SpecialType == SpecialType.System_Object) + { + encoder.Object(); + } + else if (type.SpecialType == SpecialType.System_Array) + { + // TODO array type encoder + encoder.SZArray(); + } + else + { + EncodeCustomElementType(type, encoder.ScalarType()); + } + } + + private ISymbol GetMember(INamedTypeSymbol type, string member) + { + var foundMembers = type.GetMembers(member); + var baseType = type.BaseType; + while (foundMembers.Count() == 0 && baseType != null) + { + foundMembers = baseType.GetMembers(member); + baseType = baseType.BaseType; + } + + Logger.Log("# members found: " + foundMembers.Count()); + var foundMember = foundMembers.First(); + Logger.Log("found member: " + foundMember); + return foundMember; + } + + private void EncodeNamedArguments( + INamedTypeSymbol attributeType, + IList> namedArguments, + CustomAttributeNamedArgumentsEncoder argumentsEncoder) + { + var encoder = argumentsEncoder.Count(namedArguments.Count); + foreach (var argument in namedArguments) + { + Logger.Log("named argument: " + argument.Key); + Logger.Log("value " + argument.Value); + + ITypeSymbol argumentType = null; + var attributeClassMember = GetMember(attributeType, argument.Key); + if (attributeClassMember is IFieldSymbol field) + { + argumentType = field.Type; + } + else if (attributeClassMember is IPropertySymbol property) + { + argumentType = property.Type; + } + else + { + Logger.Log("unexpected member: " + attributeClassMember.Name + " " + attributeClassMember.GetType()); + throw new InvalidOperationException(); + } + + encoder.AddArgument( + attributeClassMember is IFieldSymbol, + type => EncodeNamedArgumentType(argumentType, type), + name => name.Name(argument.Key), + literal => EncodeTypedConstant(argument.Value, literal) + ); + } + } + + private void EncodeFixedArguments(IList primitiveArguments, FixedArgumentsEncoder argumentsEncoder) + { + foreach (var argument in primitiveArguments) + { + var encoder = argumentsEncoder.AddArgument().Scalar(); + if (argument is string type) + { + encoder.SystemType(type); + } + else if (argument is INamedTypeSymbol namedTypeSymbol) + { + var typeEntity = GetTypeReference(namedTypeSymbol); + encoder.Builder.WriteReference(CodedIndex.TypeDefOrRef(typeEntity), false); + } + else + { + encoder.Constant(argument); + } + } + } + + private void AddDefaultVersionAttribute(EntityHandle parentHandle, int version = -1) + { + if (version == -1) + { + version = Version.Parse(this.version).Major; + } + + List types = new List + { + Model.Compilation.GetTypeByMetadataName("System.UInt32") + }; + + List arguments = new List + { + (UInt32) version + }; + + AddCustomAttributes("Windows.Foundation.Metadata.VersionAttribute", types, arguments, parentHandle); + } + + private void AddActivatableAttribute(EntityHandle parentHandle, UInt32 version, string factoryInterface) + { + List types = new List(2); + List arguments = new List(2); + + if (factoryInterface != null) + { + types.Add(Model.Compilation.GetTypeByMetadataName("System.Type")); + arguments.Add(factoryInterface); + } + types.Add(Model.Compilation.GetTypeByMetadataName("System.UInt32")); + arguments.Add(version); + + AddCustomAttributes("Windows.Foundation.Metadata.ActivatableAttribute", types, arguments, parentHandle); + } + + private void AddExclusiveToAttribute(EntityHandle interfaceHandle, string className) + { + List types = new List + { + Model.Compilation.GetTypeByMetadataName("System.Type") + }; + + List arguments = new List + { + className + }; + + AddCustomAttributes("Windows.Foundation.Metadata.ExclusiveToAttribute", types, arguments, interfaceHandle); + } + + private void AddStaticAttribute(EntityHandle parentHandle, UInt32 version, string staticInterface) + { + List types = new List + { + Model.Compilation.GetTypeByMetadataName("System.Type"), + Model.Compilation.GetTypeByMetadataName("System.UInt32") + }; + + List arguments = new List + { + staticInterface, + version + }; + + AddCustomAttributes("Windows.Foundation.Metadata.StaticAttribute", types, arguments, parentHandle); + } + + private void AddDefaultInterfaceImplAttribute(EntityHandle interfaceImplHandle) + { + AddCustomAttributes("Windows.Foundation.Metadata.DefaultAttribute", Array.Empty(), Array.Empty(), interfaceImplHandle); + } + + private void AddOverloadAttribute(EntityHandle methodHandle, string methodName) + { + List types = new List + { + Model.Compilation.GetTypeByMetadataName("System.String") + }; + + List arguments = new List + { + methodName + }; + + AddCustomAttributes("Windows.Foundation.Metadata.OverloadAttribute", types, arguments, methodHandle); + } + + private void AddOverloadAttributeForInterfaceMethods(TypeDeclaration interfaceTypeDeclaration) + { + // Generate unique names for any overloaded methods + foreach (var methodName in interfaceTypeDeclaration.MethodsByName.Where(symbol => symbol.Value.Count > 1)) + { + var methodSymbols = methodName.Value.Where(symbol => symbol is IMethodSymbol); + // Other members that are not methods such as properties and events can generate reserved methods + // which for the purposes of overloading are considered to be the non overloaded version. If there is no + // such function, then we consider the first encountered method to be the non overloaded version. + var skipFirstMethod = methodName.Value.Count == methodSymbols.Count(); + var lastSuffix = 1; + foreach (var method in methodSymbols) + { + if (skipFirstMethod) + { + skipFirstMethod = false; + continue; + } + + string overloadedMethodName = methodName.Key + (++lastSuffix); + while (interfaceTypeDeclaration.MethodsByName.ContainsKey(overloadedMethodName)) + { + overloadedMethodName = methodName.Key + (++lastSuffix); + } + + Logger.Log("Overloading " + methodName.Key + " with " + overloadedMethodName); + AddOverloadAttribute(interfaceTypeDeclaration.MethodDefinitions[method].First(), overloadedMethodName); + interfaceTypeDeclaration.AddMethodOverload(method, overloadedMethodName); + } + } + } + + private void AddGuidAttribute(EntityHandle parentHandle, Guid guid) + { + var uint32Type = Model.Compilation.GetTypeByMetadataName("System.UInt32"); + var uint16Type = Model.Compilation.GetTypeByMetadataName("System.UInt16"); + var byteType = Model.Compilation.GetTypeByMetadataName("System.Byte"); + List types = new List + { + uint32Type, + uint16Type, + uint16Type, + byteType, + byteType, + byteType, + byteType, + byteType, + byteType, + byteType, + byteType + }; + + var byteArray = guid.ToByteArray(); + List arguments = new List + { + BitConverter.ToUInt32(byteArray, 0), + BitConverter.ToUInt16(byteArray, 4), + BitConverter.ToUInt16(byteArray, 6), + byteArray[8], + byteArray[9], + byteArray[10], + byteArray[11], + byteArray[12], + byteArray[13], + byteArray[14], + byteArray[15] + }; + + AddCustomAttributes("Windows.Foundation.Metadata.GuidAttribute", types, arguments, parentHandle); + } + + private void AddGuidAttribute(EntityHandle parentHandle, string name) + { + Guid guid; + using (SHA1 sha = new SHA1CryptoServiceProvider()) + { + var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(name)); + guid = Helper.EncodeGuid(hash); + } + + AddGuidAttribute(parentHandle, guid); + } + + private void AddGuidAttribute(EntityHandle parentHandle, ISymbol symbol) + { + if (symbol.TryGetAttributeWithType(Model.Compilation.GetTypeByMetadataName("System.Runtime.InteropServices.GuidAttribute"), out AttributeData guidAttribute) + && guidAttribute is { ConstructorArguments.IsDefaultOrEmpty: false } + && guidAttribute.ConstructorArguments[0].Value is string guidString + && Guid.TryParse(guidString, out Guid guid)) + { + AddGuidAttribute(parentHandle, guid); + } + else + { + AddGuidAttribute(parentHandle, symbol.ToString()); + } + } + + private void AddCustomAttributes( + string attributeTypeName, + IList primitiveTypes, + IList primitiveValues, + EntityHandle parentHandle) + { + var attributeType = Model.Compilation.GetTypeByMetadataName(attributeTypeName); + Logger.Log("attribute type found " + attributeType); + if (!typeDefinitionMapping.ContainsKey(attributeTypeName)) + { + // Even if the attribute is an external non WinRT type, treat it as a projected type. + Logger.Log("adding attribute type"); + AddType(attributeType, true); + } + + Logger.Log("# constructor found: " + attributeType.Constructors.Length); + var matchingConstructor = attributeType.Constructors.Where(constructor => + constructor.Parameters.Length == primitiveValues.Count && + constructor.Parameters.Select(param => (param.Type is IErrorTypeSymbol) ? + Model.Compilation.GetTypeByMetadataName(param.Type.ToDisplayString()) : param.Type) + .SequenceEqual(primitiveTypes, SymbolEqualityComparer.Default)); + + Logger.Log("# matching constructor found: " + matchingConstructor.Count()); + Logger.Log("matching constructor found: " + matchingConstructor.First()); + + var constructorReference = typeDefinitionMapping[attributeTypeName].MethodReferences[matchingConstructor.First()]; + Logger.Log("found constructor handle: " + constructorReference.Count); + + var attributeSignature = new BlobBuilder(); + new BlobEncoder(attributeSignature) + .CustomAttributeSignature( + fixedArguments => EncodeFixedArguments(primitiveValues, fixedArguments), + namedArguments => namedArguments.Count(0) + ); + + metadataBuilder.AddCustomAttribute( + parentHandle, + constructorReference.First(), + metadataBuilder.GetOrAddBlob(attributeSignature)); + } + + private void AddCustomAttributes(IEnumerable attributes, EntityHandle parentHandle) + { + foreach (var attribute in attributes) + { + var attributeType = attribute.AttributeClass; + if (attributeType.DeclaredAccessibility != Accessibility.Public) + { + continue; + } + + if (attributeType.ToString() == "System.Runtime.InteropServices.GuidAttribute") + { + continue; + } + + // Skip the [GeneratedBindableCustomProperty] attribute. It is valid to add this on types in WinRT + // components (if they need to be exposed and implement ICustomPropertyProvider), but the attribute + // should never show up in the .winmd file (it would also cause build errors in the projections). + if (attributeType.ToString() == "WinRT.GeneratedBindableCustomPropertyAttribute") + { + continue; + } + + Logger.Log("attribute: " + attribute); + Logger.Log("attribute type: " + attributeType); + Logger.Log("attribute constructor: " + attribute.AttributeConstructor); + Logger.Log("atttribute # constructor arguments: " + attribute.ConstructorArguments.Length); + Logger.Log("atttribute # named arguments: " + attribute.NamedArguments.Length); + + if (!typeDefinitionMapping.ContainsKey(attributeType.ToString())) + { + // Even if the attribute is an external non WinRT type, treat it as a projected type. + AddType(attributeType, true); + } + + var constructorReference = typeDefinitionMapping[attributeType.ToString()].MethodReferences[attribute.AttributeConstructor]; + Logger.Log("found # constructors: " + constructorReference.Count); + + var attributeSignature = new BlobBuilder(); + new BlobEncoder(attributeSignature) + .CustomAttributeSignature( + fixedArguments => EncodeFixedArguments(attribute.ConstructorArguments, fixedArguments), + namedArguments => EncodeNamedArguments(attributeType, attribute.NamedArguments, namedArguments) + ); + + metadataBuilder.AddCustomAttribute( + parentHandle, + constructorReference.First(), + metadataBuilder.GetOrAddBlob(attributeSignature)); + } + } + + public override void VisitEnumDeclaration(EnumDeclarationSyntax node) + { + var symbol = Model.GetDeclaredSymbol(node); + + void processEnumDeclaration() + { + var enumTypeFieldAttributes = + FieldAttributes.Private | + FieldAttributes.SpecialName | + FieldAttributes.RTSpecialName; + + var enumTypeSymbol = symbol.EnumUnderlyingType; + var fieldSignature = new BlobBuilder(); + var encoder = new BlobEncoder(fieldSignature); + // TODO: special type enforcement for 64 bit + EncodeSpecialType(enumTypeSymbol.SpecialType, encoder.FieldSignature()); + + var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( + enumTypeFieldAttributes, + metadataBuilder.GetOrAddString("value__"), + metadataBuilder.GetOrAddBlob(fieldSignature)); + currentTypeDeclaration.AddField(symbol, fieldDefinitionHandle); + + base.VisitEnumDeclaration(node); + } + + AddComponentType(symbol, processEnumDeclaration); + } + + public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) + { + var symbol = Model.GetDeclaredSymbol(node); + if (!IsPublic(symbol)) + { + return; + } + + Logger.Log("defining delegate " + symbol.Name); + currentTypeDeclaration = new TypeDeclaration(symbol, true); + + base.VisitDelegateDeclaration(node); + CheckAndMarkSymbolForAttributes(symbol); + + var objType = Model.Compilation.GetTypeByMetadataName(typeof(object).FullName); + var nativeIntType = Model.Compilation.GetTypeByMetadataName(typeof(IntPtr).FullName); + + currentTypeDeclaration.AddMethod( + symbol, + ".ctor", + AddMethodDefinition( + ".ctor", + new Parameter[] { + new Parameter(objType, "object", ParameterAttributes.None), + new Parameter(nativeIntType, "method", ParameterAttributes.None) + }, + null, + false, + false, + true, + false, + true + ) + ); + + Parameter[] parameters = Parameter.GetParameters(node.ParameterList, Model); + currentTypeDeclaration.AddMethod( + symbol, + "Invoke", + AddMethodDefinition( + "Invoke", + parameters, + new Symbol(symbol.DelegateInvokeMethod.ReturnType), + false, + false, + true, + true, + true + ) + ); + + TypeAttributes typeAttributes = + TypeAttributes.Public | + TypeAttributes.WindowsRuntime | + TypeAttributes.AutoLayout | + TypeAttributes.AnsiClass | + TypeAttributes.Sealed; + + var typeDefinitionHandle = AddTypeDefinition( + typeAttributes, + symbol.ContainingNamespace.ToString(), + symbol.Name, + GetTypeReference("System", "MulticastDelegate", "mscorlib")); + currentTypeDeclaration.Handle = typeDefinitionHandle; + typeDefinitionMapping[QualifiedName(symbol, true)] = currentTypeDeclaration; + + AddGuidAttribute(typeDefinitionHandle, symbol); + } + + public void AddEventDeclaration(string eventName, ITypeSymbol eventType, ISymbol symbol, bool isStatic, bool isInterfaceParent, bool isPublic = true) + { + Logger.Log("defining event " + eventName + " with type " + eventType.ToString()); + + GetNamespaceAndTypename(eventName, out var @namespace, out var typename); + + var delegateSymbolType = eventType as INamedTypeSymbol; + EntityHandle typeReferenceHandle = GetTypeSpecification(delegateSymbolType); + EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); + Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); + + var eventDefinitionHandle = metadataBuilder.AddEvent( + EventAttributes.None, + metadataBuilder.GetOrAddString(eventName), + typeReferenceHandle); + currentTypeDeclaration.AddEvent(symbol, eventDefinitionHandle); + + string addMethodName = QualifiedName(@namespace, "add_" + typename); + var addMethod = AddMethodDefinition( + addMethodName, + new Parameter[] { new Parameter(delegateSymbolType, "handler", ParameterAttributes.In) }, + eventRegistrationToken, + !isInterfaceParent && isStatic, + isInterfaceParent, + true, + isPublic); + currentTypeDeclaration.AddMethod(symbol, addMethodName, addMethod); + + metadataBuilder.AddMethodSemantics( + eventDefinitionHandle, + MethodSemanticsAttributes.Adder, + addMethod); + + string removeMethodName = QualifiedName(@namespace, "remove_" + typename); + var removeMethod = AddMethodDefinition( + removeMethodName, + new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, + null, + !isInterfaceParent && isStatic, + isInterfaceParent, + true, + isPublic); + currentTypeDeclaration.AddMethod(symbol, removeMethodName, removeMethod); + + metadataBuilder.AddMethodSemantics( + eventDefinitionHandle, + MethodSemanticsAttributes.Remover, + removeMethod); + } + + public void AddEventDeclaration(IEventSymbol @event, bool isInterfaceParent) + { + AddEventDeclaration(@event.Name, @event.Type, @event, @event.IsStatic, isInterfaceParent, @event.ExplicitInterfaceImplementations.IsDefaultOrEmpty); + } + + void AddMethodDeclaration(IMethodSymbol method, bool isInterfaceParent) + { + Logger.Log("add method from symbol: " + method.Name); + + bool isConstructor = method.MethodKind == MethodKind.Constructor; + string methodName = isConstructor ? ".ctor" : method.Name; + var returnType = isConstructor ? null : new Symbol(method.ReturnType); + Parameter[] parameters = Parameter.GetParameters(method); + var methodDefinitionHandle = AddMethodDefinition( + methodName, + parameters, + returnType, + !isInterfaceParent && method.IsStatic, + isInterfaceParent, + isConstructor, + method.ExplicitInterfaceImplementations.IsDefaultOrEmpty); + currentTypeDeclaration.AddMethod(method, methodName, methodDefinitionHandle); + } + + void AddFactoryMethod(INamedTypeSymbol classSymbol, IMethodSymbol method) + { + Logger.Log("adding factory method: " + method.Name); + + string methodName = "Create" + classSymbol.Name; + Parameter[] parameters = Parameter.GetParameters(method); + var methodDefinitionHandle = AddMethodDefinition( + methodName, + parameters, + new Symbol(classSymbol), + false, + true, + false, + true, + true); + currentTypeDeclaration.AddMethod(method, methodName, methodDefinitionHandle); + } + + void AddComponentType(INamedTypeSymbol type, Action visitTypeDeclaration = null) + { + if (!IsPublic(type) || typeDefinitionMapping.ContainsKey(type.ToString())) + { + return; + } + + Logger.Log("defining type: " + type.TypeKind + " " + type.ToString()); + + var typeDeclaration = new TypeDeclaration(type, true); + currentTypeDeclaration = typeDeclaration; + + if (type.TypeKind == TypeKind.Class) + { + ProcessCustomMappedInterfaces(type); + } + + visitTypeDeclaration?.Invoke(); + CheckAndMarkSymbolForAttributes(type); + + bool isInterface = type.TypeKind == TypeKind.Interface; + bool hasConstructor = false; + bool hasAtLeastOneNonPublicConstructor = false; + bool hasDefaultConstructor = false; + foreach (var member in type.GetMembers()) + { + if (!IsPublic(member) || typeDeclaration.CustomMappedSymbols.Contains(member)) + { + Logger.Log(member.Kind + " member skipped " + member.Name); + + // We want to track whether a given public class has at least one non-public constructor. + // In this case, the class is still exposed to WinRT, but it's not activatable. This is + // different than a class with no explicit constructor, where we do want to generate that + // in the .winmd, and make the class activatable. But we want to avoid always emitting a + // default constructor for classes that only have non-public ones. + if (type.TypeKind == TypeKind.Class && + member is IMethodSymbol { MethodKind: MethodKind.Constructor }) + { + hasAtLeastOneNonPublicConstructor = true; + } + + continue; + } + + if (type.TypeKind == TypeKind.Struct || type.TypeKind == TypeKind.Enum) + { + if (member is IFieldSymbol field) + { + AddFieldDeclaration(field, type.TypeKind == TypeKind.Enum); + } + } + else + { + // Special case: skip members that are explicitly implementing internal interfaces. + // This allows implementing classic COM internal interfaces with non-WinRT signatures. + if (member.IsExplicitInterfaceImplementationOfInternalInterfaces()) + { + continue; + } + + if (member is IMethodSymbol method && + (method.MethodKind == MethodKind.Ordinary || + method.MethodKind == MethodKind.ExplicitInterfaceImplementation || + method.MethodKind == MethodKind.Constructor)) + { + AddMethodDeclaration(method, isInterface); + + if (method.MethodKind == MethodKind.Constructor) + { + hasConstructor = true; + hasDefaultConstructor |= (method.Parameters.Length == 0); + } + } + else if (member is IPropertySymbol property) + { + AddPropertyDeclaration(property, isInterface); + } + else if (member is IEventSymbol @event) + { + AddEventDeclaration(@event, isInterface); + } + else + { + Logger.Log("member not recognized: " + member.Kind + " name: " + member.Name); + continue; + } + } + + CheckAndMarkSymbolForAttributes(member); + } + + // Implicit constructor if none defined, but only if the type doesn't already have some non-public constructor + if (!hasConstructor && !hasAtLeastOneNonPublicConstructor && type.TypeKind == TypeKind.Class && !type.IsStatic) + { + string constructorMethodName = ".ctor"; + var methodDefinitionHandle = AddMethodDefinition( + constructorMethodName, + new Parameter[0], + null, + false, + false, + true, + true, + true); + typeDeclaration.AddMethod(type, constructorMethodName, methodDefinitionHandle); + hasDefaultConstructor = true; + } + + TypeAttributes typeAttributes = + TypeAttributes.Public | + TypeAttributes.WindowsRuntime | + TypeAttributes.AutoLayout | + TypeAttributes.AnsiClass; + + if (type.IsSealed || + type.IsStatic || + type.TypeKind == TypeKind.Struct || + type.TypeKind == TypeKind.Enum) + { + typeAttributes |= TypeAttributes.Sealed; + } + + if (type.TypeKind == TypeKind.Class && type.IsStatic) + { + typeAttributes |= TypeAttributes.Abstract; + } + + EntityHandle baseType = default; + if (isInterface) + { + typeAttributes |= + TypeAttributes.Interface | + TypeAttributes.Abstract; + } + else if (type.TypeKind == TypeKind.Class) + { + typeAttributes |= + TypeAttributes.Class | + TypeAttributes.BeforeFieldInit; + + // extends + // WinRT doesn't support projecting abstract classes. + // If the base class is one, ignore it. + if (type.BaseType != null && !type.BaseType.IsAbstract) + { + baseType = GetTypeReference(type.BaseType); + } + else + { + baseType = GetTypeReference("System", "Object", "mscorlib"); + } + } + else if (type.TypeKind == TypeKind.Struct) + { + typeAttributes |= TypeAttributes.SequentialLayout; + baseType = GetTypeReference("System", "ValueType", "mscorlib"); + } + else if (type.TypeKind == TypeKind.Enum) + { + baseType = GetTypeReference("System", "Enum", "mscorlib"); + } + + var typeDefinitionHandle = AddTypeDefinition( + typeAttributes, + type.ContainingNamespace.ToString(), + type.Name, + baseType); + typeDeclaration.Handle = typeDefinitionHandle; + + if (isInterface || type.TypeKind == TypeKind.Class) + { + // Interface implementations need to be added in order of class and then typespec. Given entries are added + // per class, that is already in order, but we need to sort by typespec. + List> implementedInterfaces = new List>(); + foreach (var implementedInterface in GetInterfaces(type)) + { + implementedInterfaces.Add(new KeyValuePair(implementedInterface, GetTypeSpecification(implementedInterface))); + } + implementedInterfaces.Sort((x, y) => CodedIndex.TypeDefOrRefOrSpec(x.Value).CompareTo(CodedIndex.TypeDefOrRefOrSpec(y.Value))); + + foreach (var implementedInterface in implementedInterfaces) + { + var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( + typeDefinitionHandle, + implementedInterface.Value); + typeDeclaration.AddInterfaceImpl(implementedInterface.Key, interfaceImplHandle); + } + } + + if (isInterface) + { + AddGuidAttribute(typeDefinitionHandle, type); + AddOverloadAttributeForInterfaceMethods(typeDeclaration); + } + + typeDefinitionMapping[QualifiedName(type, true)] = typeDeclaration; + + if (type.TypeKind == TypeKind.Class) + { + if (hasDefaultConstructor) + { + AddActivatableAttribute( + typeDeclaration.Handle, + (uint)GetVersion(type, true), + null); + } + AddSynthesizedInterfaces(typeDeclaration); + + // No synthesized default interface generated + if (typeDeclaration.DefaultInterface == null && type.Interfaces.Length != 0) + { + AddDefaultInterfaceImplAttribute(typeDeclaration.InterfaceImplDefinitions[type.Interfaces[0]]); + } + } + } + + MemberReferenceHandle AddMethodReference( + string name, + Parameter[] parameters, + Symbol returnSymbol, + INamedTypeSymbol parentType, + bool isStatic) + { + var methodSignature = new BlobBuilder(); + new BlobEncoder(methodSignature) + .MethodSignature( + SignatureCallingConvention.Default, + 0, + !isStatic) + .Parameters( + parameters.Length, + returnType => EncodeReturnType(returnSymbol, returnType), + parametersEncoder => EncodeParameters(parameters, parametersEncoder) + ); + + var referenceHandle = metadataBuilder.AddMemberReference( + GetTypeSpecification(parentType), + metadataBuilder.GetOrAddString(name), + metadataBuilder.GetOrAddBlob(methodSignature) + ); + return referenceHandle; + } + + MemberReferenceHandle AddMethodReference(IMethodSymbol method) + { + Logger.Log("adding method reference: " + method.Name); + + bool isInterfaceParent = method.ContainingType.TypeKind == TypeKind.Interface; + string methodName = method.MethodKind == MethodKind.Constructor ? ".ctor" : method.Name; + Parameter[] parameters = Parameter.GetParameters(method); + var referenceHandle = AddMethodReference( + methodName, + parameters, + new Symbol(method.ReturnType), + method.ContainingType, + !isInterfaceParent && method.IsStatic); + currentTypeDeclaration.AddMethodReference(method, referenceHandle); + return referenceHandle; + } + + public void AddPropertyReference(string name, Symbol type, ISymbol symbol, INamedTypeSymbol parent, bool setMethod) + { + Logger.Log("adding property reference: " + name); + + if (setMethod) + { + var setMethodReference = AddMethodReference( + "put_" + name, + new Parameter[] { new Parameter(type, "value", ParameterAttributes.In) }, + null, + parent, + false); + currentTypeDeclaration.AddMethodReference(symbol, setMethodReference); + } + + var getMethodReference = AddMethodReference( + "get_" + name, + new Parameter[0], + type, + parent, + false); + currentTypeDeclaration.AddMethodReference(symbol, getMethodReference); + } + + public void AddPropertyReference(IPropertySymbol property) + { + AddPropertyReference( + property.Name, + new Symbol(property.Type), + property, + property.ContainingType, + property.SetMethod != null); + } + + public void AddEventReference(string eventName, ITypeSymbol eventType, ISymbol symbol, INamedTypeSymbol parent) + { + Logger.Log("adding event reference: " + eventName); + + EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); + Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); + + var addMethodReference = AddMethodReference( + "add_" + eventName, + new Parameter[] { new Parameter(eventType, "handler", ParameterAttributes.In) }, + eventRegistrationToken, + parent, + false); + currentTypeDeclaration.AddMethodReference(symbol, addMethodReference); + + var removeMethodReference = AddMethodReference( + "remove_" + eventName, + new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, + null, + parent, + false); + currentTypeDeclaration.AddMethodReference(symbol, removeMethodReference); + } + + public void AddEventReference(IEventSymbol @event) + { + AddEventReference(@event.Name, @event.Type, @event, @event.ContainingType); + } + + void AddProjectedType(INamedTypeSymbol type, string projectedTypeOverride = null) + { + currentTypeDeclaration = new TypeDeclaration(type); + + foreach (var member in type.GetMembers()) + { + if (member is IMethodSymbol method && + (method.MethodKind == MethodKind.Ordinary || + method.MethodKind == MethodKind.ExplicitInterfaceImplementation || + method.MethodKind == MethodKind.Constructor)) + { + AddMethodReference(method); + } + else if (member is IPropertySymbol property) + { + AddPropertyReference(property); + } + else if (member is IEventSymbol @event) + { + AddEventReference(@event); + } + else + { + Logger.Log("member not recognized: " + member.Kind + " " + member.Name); + } + } + + typeDefinitionMapping[projectedTypeOverride ?? QualifiedName(type, true)] = currentTypeDeclaration; + } + + void AddMappedType(INamedTypeSymbol type) + { + currentTypeDeclaration = new TypeDeclaration(type); + WriteCustomMappedTypeMembers(type, false); + typeDefinitionMapping[QualifiedName(type, true)] = currentTypeDeclaration; + } + + enum SynthesizedInterfaceType + { + Static, + Factory, + Default + } + + string GetSynthesizedInterfaceName(string className, SynthesizedInterfaceType type) + { + // TODO: handle existing types by appending number suffix + return "I" + className + + type switch + { + SynthesizedInterfaceType.Default => "Class", + SynthesizedInterfaceType.Factory => "Factory", + SynthesizedInterfaceType.Static => "Static", + _ => "", + }; + } + + void AddSynthesizedInterfaces(TypeDeclaration classDeclaration) + { + HashSet classMembersFromInterfaces = new(SymbolEqualityComparer.Default); + INamedTypeSymbol classSymbol = classDeclaration.Node as INamedTypeSymbol; + foreach (var @interface in classSymbol.AllInterfaces) + { + foreach (var interfaceMember in @interface.GetMembers()) + { + var classMember = classSymbol.FindImplementationForInterfaceMember(interfaceMember); + if (classMember == null || !classDeclaration.MethodDefinitions.ContainsKey(classMember)) + { + continue; + } + + classMembersFromInterfaces.Add(classMember); + classDeclaration.ClassInterfaceMemberMapping[classMember] = interfaceMember; + + // Mark class members whose interface declaration has attributes + // so that we can propagate them later. + if (interfaceMember.GetAttributes().Any()) + { + classDeclaration.SymbolsWithAttributes.Add(classMember); + } + } + } + + AddSynthesizedInterface( + classDeclaration, + SynthesizedInterfaceType.Static, + classMembersFromInterfaces); + + AddSynthesizedInterface( + classDeclaration, + SynthesizedInterfaceType.Factory, + classMembersFromInterfaces); + + AddSynthesizedInterface( + classDeclaration, + SynthesizedInterfaceType.Default, + classMembersFromInterfaces); + + // TODO: address overridable and composable interfaces. + } + + void CheckAndMarkSynthesizedInterfaceSymbolForAttributes(ISymbol symbol, TypeDeclaration classDeclaration) + { + // Check the class declaration if the symbol had any attributes marked for it, + // and if so propagate it to the synthesized interface. + if (classDeclaration.SymbolsWithAttributes.Contains(symbol)) + { + currentTypeDeclaration.SymbolsWithAttributes.Add(symbol); + } + } + + void CheckAndMarkSymbolForAttributes(ISymbol symbol) + { + if (symbol.GetAttributes().Any()) + { + currentTypeDeclaration.SymbolsWithAttributes.Add(symbol); + } + } + + void AddSynthesizedInterface( + TypeDeclaration classDeclaration, + SynthesizedInterfaceType interfaceType, + HashSet classMembersFromInterfaces) + { + var typeDeclaration = new TypeDeclaration(); + currentTypeDeclaration = typeDeclaration; + + bool hasTypes = false; + INamedTypeSymbol classSymbol = classDeclaration.Node as INamedTypeSymbol; + + // Each class member results in some form of method definition, + // so using that to our advantage to get public members. + foreach (var classMember in classDeclaration.MethodDefinitions) + { + if (interfaceType == SynthesizedInterfaceType.Factory && + classMember.Key is IMethodSymbol constructorMethod && + constructorMethod.MethodKind == MethodKind.Constructor && + constructorMethod.Parameters.Length != 0) + { + hasTypes = true; + AddFactoryMethod(classSymbol, constructorMethod); + CheckAndMarkSynthesizedInterfaceSymbolForAttributes(classMember.Key, classDeclaration); + } + else if ((interfaceType == SynthesizedInterfaceType.Default && !classMember.Key.IsStatic && + !classMembersFromInterfaces.Contains(classMember.Key)) || + (interfaceType == SynthesizedInterfaceType.Static && classMember.Key.IsStatic)) + { + if (classMember.Key is IMethodSymbol method && method.MethodKind == MethodKind.Ordinary) + { + AddMethodDeclaration(method, true); + } + else if (classMember.Key is IPropertySymbol property) + { + AddPropertyDeclaration(property, true); + } + else if (classMember.Key is IEventSymbol @event) + { + AddEventDeclaration(@event, true); + } + else + { + Logger.Log("member for synthesized interface not recognized: " + classMember.Key.Kind + " " + classMember.Key.Name); + continue; + } + + CheckAndMarkSynthesizedInterfaceSymbolForAttributes(classMember.Key, classDeclaration); + hasTypes = true; + } + } + + TypeAttributes typeAttributes = + TypeAttributes.NotPublic | + TypeAttributes.WindowsRuntime | + TypeAttributes.AutoLayout | + TypeAttributes.AnsiClass | + TypeAttributes.Interface | + TypeAttributes.Abstract; + + if (hasTypes || (interfaceType == SynthesizedInterfaceType.Default && classSymbol.Interfaces.Length == 0)) + { + Logger.Log("writing generated interface " + interfaceType); + var interfaceName = GetSynthesizedInterfaceName(classDeclaration.Node.Name, interfaceType); + var typeDefinitionHandle = AddTypeDefinition( + typeAttributes, + classDeclaration.Node.ContainingNamespace.ToString(), + interfaceName, + default); + typeDeclaration.Handle = typeDefinitionHandle; + + string qualifiedInterfaceName = QualifiedName(classDeclaration.Node.ContainingNamespace.ToString(), interfaceName); + typeDefinitionMapping[qualifiedInterfaceName] = typeDeclaration; + + if (interfaceType == SynthesizedInterfaceType.Default) + { + classDeclaration.DefaultInterface = qualifiedInterfaceName; + var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( + classDeclaration.Handle, + GetTypeReference(classDeclaration.Node.ContainingNamespace.ToString(), interfaceName, assembly)); + classDeclaration.AddInterfaceImpl(classSymbol, interfaceImplHandle); + AddDefaultInterfaceImplAttribute(interfaceImplHandle); + } + + AddDefaultVersionAttribute(typeDefinitionHandle, GetVersion(classSymbol, true)); + AddGuidAttribute(typeDefinitionHandle, interfaceName); + AddExclusiveToAttribute(typeDefinitionHandle, classSymbol.ToString()); + AddOverloadAttributeForInterfaceMethods(typeDeclaration); + + if (interfaceType == SynthesizedInterfaceType.Factory) + { + AddActivatableAttribute(classDeclaration.Handle, (uint)GetVersion(classSymbol, true), qualifiedInterfaceName); + } + else if (interfaceType == SynthesizedInterfaceType.Static) + { + classDeclaration.StaticInterface = qualifiedInterfaceName; + AddStaticAttribute(classDeclaration.Handle, (uint)GetVersion(classSymbol, true), qualifiedInterfaceName); + } + } + } + + private int GetVersion(INamedTypeSymbol type, bool setDefaultIfNotSet = false) + { + var versionAttribute = type.GetAttributes(). + Where(attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "VersionAttribute") == 0); + if (!versionAttribute.Any()) + { + return setDefaultIfNotSet ? Version.Parse(this.version).Major : -1; + } + + uint version = (uint)versionAttribute.First().ConstructorArguments[0].Value; + return (int)version; + } + + void AddType(INamedTypeSymbol type, bool treatAsProjectedType = false) + { + Logger.Log("add type: " + type.ToString()); + bool isProjectedType = type.GetAttributes(). + Any(attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeTypeAttribute") == 0); + var qualifiedName = QualifiedName(type); + if (isProjectedType) + { + AddProjectedType(type); + } + else if (mapper.HasMappingForType(qualifiedName)) + { + var (@namespace, name, assembly, isSystemType, _) = mapper.GetMappedType(qualifiedName).GetMapping(); + if (isSystemType) + { + var projectedType = Model.Compilation.GetTypeByMetadataName(QualifiedName(@namespace, name)); + AddProjectedType(projectedType); + } + else + { + AddMappedType(type); + } + } + else if (treatAsProjectedType) + { + // Prioritize any mapped types before treating an attribute as a projected type. + AddProjectedType(type); + } + else + { + AddComponentType(type); + } + } + + void AddCustomAttributes(TypeDeclaration typeDeclaration, string interfaceName = null) + { + foreach (var node in typeDeclaration.SymbolsWithAttributes) + { + EntityHandle parentHandle; + if (node is INamedTypeSymbol namedType) + { + // Attributes on classes don't propagate to synthesized interfaces. + if (interfaceName != null) + { + continue; + } + + parentHandle = typeDefinitionMapping[namedType.ToString()].Handle; + } + else + { + var typeName = interfaceName ?? node.ContainingType.ToString(); + + if (node is IMethodSymbol method) + { + parentHandle = typeDefinitionMapping[typeName].MethodDefinitions[method][0]; + } + else if (node is IPropertySymbol property) + { + parentHandle = typeDefinitionMapping[typeName].PropertyDefinitions[property]; + } + else if (node is IEventSymbol @event) + { + parentHandle = typeDefinitionMapping[typeName].EventDefinitions[@event]; + } + else + { + Logger.Log("node not recognized " + node.Kind + " name: " + node.Name); + continue; + } + } + + // Add attributes from both the class member declaration and its interface member declaration. + HashSet attributes = new HashSet(node.GetAttributes(), new AttributeDataComparer()); + if (typeDeclaration.ClassInterfaceMemberMapping.ContainsKey(node)) + { + attributes.UnionWith(typeDeclaration.ClassInterfaceMemberMapping[node].GetAttributes()); + } + AddCustomAttributes(attributes, parentHandle); + } + } + + public void FinalizeGeneration() + { + Logger.Log("finalizing"); + var classTypeDeclarations = typeDefinitionMapping.Values + .Where(declaration => declaration.Node is INamedTypeSymbol symbol && symbol.TypeKind == TypeKind.Class) + .ToList(); + + foreach (var classTypeDeclaration in classTypeDeclarations) + { + INamedTypeSymbol classSymbol = classTypeDeclaration.Node as INamedTypeSymbol; + + Logger.Log("finalizing class " + QualifiedName(classSymbol)); + foreach (var implementedInterface in GetInterfaces(classSymbol)) + { + var implementedInterfaceQualifiedNameWithGenerics = QualifiedName(implementedInterface, true); + if (!typeDefinitionMapping.ContainsKey(implementedInterfaceQualifiedNameWithGenerics)) + { + AddType(implementedInterface); + } + + Logger.Log("finalizing interface " + implementedInterfaceQualifiedNameWithGenerics); + var interfaceTypeDeclaration = typeDefinitionMapping[implementedInterfaceQualifiedNameWithGenerics]; + if (mapper.HasMappingForType(QualifiedName(implementedInterface))) + { + Logger.Log("adding MethodImpls for custom mapped interface"); + foreach (var interfaceMember in interfaceTypeDeclaration.MethodReferences) + { + var interfaceMemberMethodDefinitions = interfaceMember.Value; + var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[implementedInterface]; + for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) + { + metadataBuilder.AddMethodImplementation( + classTypeDeclaration.Handle, + classMemberMethodDefinitions[idx], + interfaceMemberMethodDefinitions[idx]); + } + } + } + else + { + Logger.Log("adding MethodImpls for interface"); + foreach (var interfaceMember in interfaceTypeDeclaration.MethodReferences) + { + var classMember = classSymbol.FindImplementationForInterfaceMember(interfaceMember.Key); + if (classTypeDeclaration.MethodDefinitions.ContainsKey(classMember)) + { + var interfaceMemberMethodDefinitions = interfaceMember.Value; + var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[classMember]; + for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) + { + metadataBuilder.AddMethodImplementation( + classTypeDeclaration.Handle, + classMemberMethodDefinitions[idx], + interfaceMemberMethodDefinitions[idx]); + } + + // If method overloaded in interface, overload in class too. + if (interfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) + { + AddOverloadAttribute(classMemberMethodDefinitions.First(), interfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key]); + } + } + } + } + } + + if (classTypeDeclaration.DefaultInterface != null) + { + Logger.Log("finalizing default interface " + classTypeDeclaration.DefaultInterface); + var defaultInterfaceTypeDeclaration = typeDefinitionMapping[classTypeDeclaration.DefaultInterface]; + foreach (var interfaceMember in defaultInterfaceTypeDeclaration.MethodReferences) + { + if (classTypeDeclaration.MethodDefinitions.ContainsKey(interfaceMember.Key)) + { + var interfaceMemberMethodDefinitions = interfaceMember.Value; + var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[interfaceMember.Key]; + for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) + { + metadataBuilder.AddMethodImplementation( + classTypeDeclaration.Handle, + classMemberMethodDefinitions[idx], + interfaceMemberMethodDefinitions[idx]); + } + + // If method overloaded in interface, overload in class too. + if (defaultInterfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) + { + AddOverloadAttribute(classMemberMethodDefinitions.First(), defaultInterfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key]); + } + } + } + } + + if (classTypeDeclaration.StaticInterface != null) + { + Logger.Log("finalizing static interface " + classTypeDeclaration.StaticInterface); + var staticInterfaceTypeDeclaration = typeDefinitionMapping[classTypeDeclaration.StaticInterface]; + foreach (var interfaceMember in staticInterfaceTypeDeclaration.MethodReferences) + { + // If method overloaded in static interface, overload in class too. + if (classTypeDeclaration.MethodDefinitions.ContainsKey(interfaceMember.Key) && + staticInterfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) + { + AddOverloadAttribute( + classTypeDeclaration.MethodDefinitions[interfaceMember.Key].First(), + staticInterfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key] + ); + } + } + } + } + + Logger.Log("adding default version attributes"); + var declarations = typeDefinitionMapping.Values + .Where(declaration => declaration.Node != null) + .ToList(); + foreach (var declaration in declarations) + { + INamedTypeSymbol namedType = declaration.Node as INamedTypeSymbol; + string qualifiedNameWithGenerics = QualifiedName(namedType, true); + if (typeDefinitionMapping[qualifiedNameWithGenerics].Handle != default && GetVersion(namedType) == -1) + { + AddDefaultVersionAttribute(typeDefinitionMapping[qualifiedNameWithGenerics].Handle); + } + } + + Logger.Log("adding custom attributes"); + var typeDeclarationsWithAttributes = typeDefinitionMapping.Values + .Where(declaration => !declaration.IsSynthesizedInterface && declaration.SymbolsWithAttributes.Any()) + .ToList(); + foreach (var typeDeclaration in typeDeclarationsWithAttributes) + { + AddCustomAttributes(typeDeclaration); + + if (typeDeclaration.Node is INamedTypeSymbol symbol && symbol.TypeKind == TypeKind.Class) + { + if (!string.IsNullOrEmpty(typeDeclaration.DefaultInterface)) + { + Logger.Log("adding attributes for default interface " + typeDeclaration.DefaultInterface); + AddCustomAttributes(typeDefinitionMapping[typeDeclaration.DefaultInterface], typeDeclaration.DefaultInterface); + } + + if (!string.IsNullOrEmpty(typeDeclaration.StaticInterface)) + { + Logger.Log("adding attributes for static interface " + typeDeclaration.StaticInterface); + AddCustomAttributes(typeDefinitionMapping[typeDeclaration.StaticInterface], typeDeclaration.StaticInterface); + } + } + } + } + + public void GenerateWinRTExposedClassAttributes(GeneratorExecutionContext context) + { + bool IsWinRTType(ISymbol symbol, TypeMapper mapper) + { + if (!SymbolEqualityComparer.Default.Equals(symbol.ContainingAssembly, context.Compilation.Assembly)) + { + return GeneratorHelper.IsWinRTType(symbol, (symbol, mapper) => IsWinRTType(symbol, mapper), mapper); + } + + if (symbol is INamedTypeSymbol namedType) + { + if (namedType.TypeKind == TypeKind.Interface) + { + // Interfaces which are allowed to be implemented on authored types but + // aren't WinRT interfaces. + return !ImplementedInterfacesWithoutMapping.Contains(QualifiedName(namedType)); + } + + return namedType.SpecialType != SpecialType.System_Object && + namedType.SpecialType != SpecialType.System_Enum && + namedType.SpecialType != SpecialType.System_ValueType && + namedType.SpecialType != SpecialType.System_Delegate && + namedType.SpecialType != SpecialType.System_MulticastDelegate; + } + + // In an authoring component, diagnostics prevents you from using non-WinRT types + // by the time we get to here. + return true; + } + + // If an older CsWinRT version is referenced, it is used to generate the projection. + // The projection generated by it won't be marked partial to generate the attribute on it + // and we also don't support it with the new scenarios without updating CsWinRT package + // So skip generating them. + if (GeneratorHelper.IsOldCsWinRTExe(context)) + { + return; + } + + List vtableAttributesToAdd = new(); + HashSet vtableAttributesToAddOnLookupTable = new(); + + Func isManagedOnlyTypeFunc = GeneratorHelper.IsManagedOnlyType(context.Compilation); + + foreach (var typeDeclaration in typeDefinitionMapping.Values) + { + if (typeDeclaration.IsComponentType && + typeDeclaration.Node is INamedTypeSymbol symbol && + symbol.TypeKind == TypeKind.Class && + !symbol.IsStatic) + { + var vtableAttribute = WinRTAotSourceGenerator.GetVtableAttributeToAdd(symbol, isManagedOnlyTypeFunc, IsWinRTType, mapper, context.Compilation, true, typeDeclaration.DefaultInterface); + if (vtableAttribute != default) + { + vtableAttributesToAdd.Add(vtableAttribute); + } + WinRTAotSourceGenerator.AddVtableAdapterTypeForKnownInterface(symbol, context.Compilation, isManagedOnlyTypeFunc, IsWinRTType, mapper, vtableAttributesToAddOnLookupTable); + } + } + + string escapedAssemblyName = GeneratorHelper.EscapeTypeNameForIdentifier(context.Compilation.AssemblyName); + if (vtableAttributesToAdd.Any() || vtableAttributesToAddOnLookupTable.Any()) + { + WinRTAotSourceGenerator.GenerateCCWForGenericInstantiation( + context.AddSource, + vtableAttributesToAdd.SelectMany(static (vtableAttribute, _) => vtableAttribute.GenericInterfaces). + Union(vtableAttributesToAddOnLookupTable.SelectMany(static (vtableAttribute, _) => vtableAttribute.GenericInterfaces)). + Distinct(). + ToImmutableArray(), + escapedAssemblyName); + } + + if (vtableAttributesToAdd.Any()) + { + WinRTAotSourceGenerator.GenerateVtableAttributes(context.AddSource, vtableAttributesToAdd.ToImmutableArray(), false, escapedAssemblyName); + } + + if (vtableAttributesToAddOnLookupTable.Any()) + { + WinRTAotSourceGenerator.GenerateVtableLookupTable(context.AddSource, (vtableAttributesToAddOnLookupTable.ToImmutableArray(), (new CsWinRTAotOptimizerProperties(true, true, true, false), escapedAssemblyName)), true); + } + } + + public bool IsPublic(ISymbol symbol) + { + // Check that the type has either public accessibility, or is an explicit interface implementation + if (symbol.DeclaredAccessibility == Accessibility.Public || + symbol is IMethodSymbol method && !method.ExplicitInterfaceImplementations.IsDefaultOrEmpty || + symbol is IPropertySymbol property && !property.ExplicitInterfaceImplementations.IsDefaultOrEmpty || + symbol is IEventSymbol @event && !@event.ExplicitInterfaceImplementations.IsDefaultOrEmpty) + { + // If we have a containing type, we also check that it's publicly accessible + return symbol.ContainingType is not { } containingType || containingType.IsPubliclyAccessible(); + } + + return false; + } + + public void GetNamespaceAndTypename(string qualifiedName, out string @namespace, out string typename) + { + var idx = qualifiedName.LastIndexOf('.'); + if (idx == -1) + { + @namespace = ""; + typename = qualifiedName; + } + else + { + @namespace = qualifiedName.Substring(0, idx); + typename = qualifiedName.Substring(idx + 1); + } + } + + public static string QualifiedName(string @namespace, string identifier) + { + if (string.IsNullOrEmpty(@namespace)) + { + return identifier; + } + return string.Join(".", @namespace, identifier); + } + + public static string GetGenericName(ISymbol symbol, bool includeGenerics = false) + { + string name = symbol.Name; + if (symbol is INamedTypeSymbol namedType && namedType.TypeArguments.Length != 0) + { + name += "`" + namedType.TypeArguments.Length; + if (includeGenerics) + { + name += string.Format("<{0}>", string.Join(", ", namedType.TypeArguments)); + } + } + return name; + } + + public static string QualifiedName(ISymbol symbol, bool includeGenerics = false) + { + return QualifiedName(symbol.ContainingNamespace.ToString(), GetGenericName(symbol, includeGenerics)); + } + } +} diff --git a/src/Authoring/cswinmd/CsWinMD.csproj b/src/Authoring/cswinmd/CsWinMD.csproj index 783ef7adf..a86d5081a 100644 --- a/src/Authoring/cswinmd/CsWinMD.csproj +++ b/src/Authoring/cswinmd/CsWinMD.csproj @@ -30,7 +30,7 @@ - + diff --git a/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj b/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj index 0f1a12d5c..be08e87f7 100644 --- a/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj +++ b/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/Projections/Windows/Windows.csproj b/src/Projections/Windows/Windows.csproj index 5eec63b47..3dde59ba7 100644 --- a/src/Projections/Windows/Windows.csproj +++ b/src/Projections/Windows/Windows.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj b/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj index 53de8e4f9..218108cf4 100644 --- a/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj +++ b/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -13,7 +13,7 @@ - + diff --git a/src/cswinrt.sln b/src/cswinrt.sln index 11da8efdf..9b58abe8c 100644 --- a/src/cswinrt.sln +++ b/src/cswinrt.sln @@ -83,7 +83,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinRT.Host.Shim", "Authorin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestHost.ProbeByClass", "Projections\TestHost.ProbeByClass\TestHost.ProbeByClass.csproj", "{EF3326B5-716F-41D2-AB30-4EFAB30955E2}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinRT.SourceGenerator", "Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.csproj", "{E0C26D3A-504A-4826-BAE2-DE775F865B2A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinRT.SourceGenerator.Roslyn4080", "Authoring\WinRT.SourceGenerator.Roslyn4080\WinRT.SourceGenerator.Roslyn4080.csproj", "{E0C26D3A-504A-4826-BAE2-DE775F865B2A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthoringTest", "Tests\AuthoringTest\AuthoringTest.csproj", "{41E2A272-150F-42F5-AD40-047AAD9088A0}" EndProject From aa09f20c959f8856f38e6d78bd65b659bd2ad0c7 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 18:30:34 -0800 Subject: [PATCH 16/40] Use shared project for generator --- .../WinRT.SourceGenerator.Roslyn4080.csproj | 18 +----- .../AnalyzerReleases.Shipped.md | 0 .../AnalyzerReleases.Unshipped.md | 0 .../AotOptimizer.cs | 0 .../CollectionExpressionAnalyzer.cs | 0 .../CollectionExpressionIDE0300Suppressor.cs | 0 .../CollectionExpressionIDE0303Suppressor.cs | 0 .../CollectionExpressionIDE0305Suppressor.cs | 0 .../CollectionExpressionSuppressor.cs | 0 .../CsWinRTDiagnosticStrings.Designer.cs | 2 +- .../CsWinRTDiagnosticStrings.resx | 0 .../DiagnosticHelpers.cs | 0 .../DiagnosticUtils.cs | 0 .../Extensions/SymbolExtensions.cs | 0 .../Generator.cs | 0 .../GenericVtableInitializerStrings.cs | 0 .../Helper.cs | 0 .../ImmutableEquatableArray.cs | 0 .../Logger.cs | 0 ...eReferencedActivationFactoriesGenerator.cs | 0 .../Properties/launchSettings.json | 0 .../RcwReflectionFallbackGenerator.cs | 0 .../ResX/de-DE/CsWinRTDiagnosticStrings.resx | 0 .../ResX/es-ES/CsWinRTDiagnosticStrings.resx | 0 .../ResX/fr-FR/CsWinRTDiagnosticStrings.resx | 0 .../ResX/it-IT/CsWinRTDiagnosticStrings.resx | 0 .../ResX/ja-JP/CsWinRTDiagnosticStrings.resx | 0 .../ResX/ko-KR/CsWinRTDiagnosticStrings.resx | 0 .../ResX/pt-BR/CsWinRTDiagnosticStrings.resx | 0 .../ResX/ru-RU/CsWinRTDiagnosticStrings.resx | 0 .../ResX/zh-CN/CsWinRTDiagnosticStrings.resx | 0 .../ResX/zh-TW/CsWinRTDiagnosticStrings.resx | 0 .../TypeMapper.cs | 0 .../WinRT.SourceGenerator.projitems | 62 +++++++++++++++++++ .../WinRT.SourceGenerator.shproj | 13 ++++ .../WinRTAotCodeFixer.cs | 0 .../WinRTRules.cs | 0 .../WinRTSuppressions.cs | 0 .../WinRTTypeWriter.cs | 0 src/cswinrt.sln | 7 +++ 40 files changed, 84 insertions(+), 18 deletions(-) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/AnalyzerReleases.Shipped.md (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/AnalyzerReleases.Unshipped.md (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/AotOptimizer.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/CollectionExpressions/CollectionExpressionAnalyzer.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/CollectionExpressions/CollectionExpressionSuppressor.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/CsWinRTDiagnosticStrings.Designer.cs (99%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/DiagnosticHelpers.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/DiagnosticUtils.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/Extensions/SymbolExtensions.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/Generator.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/GenericVtableInitializerStrings.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/Helper.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ImmutableEquatableArray.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/Logger.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/MergeReferencedActivationFactoriesGenerator.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/Properties/launchSettings.json (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/RcwReflectionFallbackGenerator.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/de-DE/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/es-ES/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/fr-FR/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/it-IT/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/ja-JP/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/ko-KR/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/pt-BR/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/ru-RU/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/zh-CN/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/ResX/zh-TW/CsWinRTDiagnosticStrings.resx (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/TypeMapper.cs (100%) create mode 100644 src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems create mode 100644 src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.shproj rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/WinRTAotCodeFixer.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/WinRTRules.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/WinRTSuppressions.cs (100%) rename src/Authoring/{WinRT.SourceGenerator.Roslyn4080 => WinRT.SourceGenerator}/WinRTTypeWriter.cs (100%) diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj index c88087a73..a4dd37506 100644 --- a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj @@ -27,22 +27,6 @@ - - - - - - - True - True - CsWinRTDiagnosticStrings.resx - - - - - ResXFileCodeGenerator - CsWinRTDiagnosticStrings.Designer.cs - - + diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Shipped.md b/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Shipped.md rename to src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Unshipped.md b/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Unshipped.md similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/AnalyzerReleases.Unshipped.md rename to src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Unshipped.md diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/AotOptimizer.cs b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/AotOptimizer.cs rename to src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionAnalyzer.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionAnalyzer.cs rename to src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs rename to src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs rename to src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs rename to src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionSuppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/CollectionExpressions/CollectionExpressionSuppressor.cs rename to src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.Designer.cs b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs similarity index 99% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.Designer.cs rename to src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs index 4fe2fe15b..6e27f64f5 100644 --- a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.Designer.cs +++ b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace WinRT.SourceGenerator.Roslyn4080 { +namespace WinRT.SourceGenerator { using System; diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/DiagnosticHelpers.cs b/src/Authoring/WinRT.SourceGenerator/DiagnosticHelpers.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/DiagnosticHelpers.cs rename to src/Authoring/WinRT.SourceGenerator/DiagnosticHelpers.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/DiagnosticUtils.cs b/src/Authoring/WinRT.SourceGenerator/DiagnosticUtils.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/DiagnosticUtils.cs rename to src/Authoring/WinRT.SourceGenerator/DiagnosticUtils.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Extensions/SymbolExtensions.cs b/src/Authoring/WinRT.SourceGenerator/Extensions/SymbolExtensions.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/Extensions/SymbolExtensions.cs rename to src/Authoring/WinRT.SourceGenerator/Extensions/SymbolExtensions.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Generator.cs b/src/Authoring/WinRT.SourceGenerator/Generator.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/Generator.cs rename to src/Authoring/WinRT.SourceGenerator/Generator.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/GenericVtableInitializerStrings.cs b/src/Authoring/WinRT.SourceGenerator/GenericVtableInitializerStrings.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/GenericVtableInitializerStrings.cs rename to src/Authoring/WinRT.SourceGenerator/GenericVtableInitializerStrings.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Helper.cs b/src/Authoring/WinRT.SourceGenerator/Helper.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/Helper.cs rename to src/Authoring/WinRT.SourceGenerator/Helper.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ImmutableEquatableArray.cs b/src/Authoring/WinRT.SourceGenerator/ImmutableEquatableArray.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ImmutableEquatableArray.cs rename to src/Authoring/WinRT.SourceGenerator/ImmutableEquatableArray.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Logger.cs b/src/Authoring/WinRT.SourceGenerator/Logger.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/Logger.cs rename to src/Authoring/WinRT.SourceGenerator/Logger.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/MergeReferencedActivationFactoriesGenerator.cs b/src/Authoring/WinRT.SourceGenerator/MergeReferencedActivationFactoriesGenerator.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/MergeReferencedActivationFactoriesGenerator.cs rename to src/Authoring/WinRT.SourceGenerator/MergeReferencedActivationFactoriesGenerator.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/Properties/launchSettings.json b/src/Authoring/WinRT.SourceGenerator/Properties/launchSettings.json similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/Properties/launchSettings.json rename to src/Authoring/WinRT.SourceGenerator/Properties/launchSettings.json diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/RcwReflectionFallbackGenerator.cs b/src/Authoring/WinRT.SourceGenerator/RcwReflectionFallbackGenerator.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/RcwReflectionFallbackGenerator.cs rename to src/Authoring/WinRT.SourceGenerator/RcwReflectionFallbackGenerator.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/de-DE/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/de-DE/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/de-DE/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/de-DE/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/es-ES/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/es-ES/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/es-ES/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/es-ES/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/fr-FR/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/fr-FR/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/fr-FR/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/fr-FR/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/it-IT/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/it-IT/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/it-IT/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/it-IT/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ja-JP/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/ja-JP/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ja-JP/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/ja-JP/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ko-KR/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/ko-KR/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ko-KR/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/ko-KR/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/pt-BR/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/pt-BR/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/pt-BR/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/pt-BR/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ru-RU/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/ru-RU/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/ru-RU/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/ru-RU/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-CN/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/zh-CN/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-CN/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/zh-CN/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-TW/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/ResX/zh-TW/CsWinRTDiagnosticStrings.resx similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/ResX/zh-TW/CsWinRTDiagnosticStrings.resx rename to src/Authoring/WinRT.SourceGenerator/ResX/zh-TW/CsWinRTDiagnosticStrings.resx diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/TypeMapper.cs b/src/Authoring/WinRT.SourceGenerator/TypeMapper.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/TypeMapper.cs rename to src/Authoring/WinRT.SourceGenerator/TypeMapper.cs diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems new file mode 100644 index 000000000..f1350d2c0 --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems @@ -0,0 +1,62 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + b0e5e9cc-5fb4-4f94-bd54-115a91a6ae9d + + + WinRT.SourceGenerator + + + + + + + + + + + + + CsWinRTDiagnosticStrings.resx + True + True + + + + + + + + + + + + + + + + + + + + CsWinRTDiagnosticStrings.Designer.cs + ResXFileCodeGenerator + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.shproj b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.shproj new file mode 100644 index 000000000..c1ba05e5b --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.shproj @@ -0,0 +1,13 @@ + + + + b0e5e9cc-5fb4-4f94-bd54-115a91a6ae9d + 14.0 + + + + + + + + \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTAotCodeFixer.cs b/src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTAotCodeFixer.cs rename to src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTRules.cs b/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTRules.cs rename to src/Authoring/WinRT.SourceGenerator/WinRTRules.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTSuppressions.cs b/src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTSuppressions.cs rename to src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs similarity index 100% rename from src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRTTypeWriter.cs rename to src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs diff --git a/src/cswinrt.sln b/src/cswinrt.sln index 9b58abe8c..ed013a653 100644 --- a/src/cswinrt.sln +++ b/src/cswinrt.sln @@ -176,6 +176,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OptInMode", "Tests\Function EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGeneratorTest", "Tests\SourceGeneratorTest\SourceGeneratorTest.csproj", "{CB7C338F-3850-4744-A1EA-3DC47B703C4A}" EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "WinRT.SourceGenerator", "Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.shproj", "{B0E5E9CC-5FB4-4F94-BD54-115A91A6AE9D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -913,8 +915,13 @@ Global {54D6C10E-19C9-4BCF-B237-682C0120FC1F} = {5ECC38F0-16FD-47E1-B8DC-8C474008AD55} {FFC0B06E-78E7-44D5-8E67-8FE5744CE071} = {5ECC38F0-16FD-47E1-B8DC-8C474008AD55} {CB7C338F-3850-4744-A1EA-3DC47B703C4A} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} + {B0E5E9CC-5FB4-4F94-BD54-115A91A6AE9D} = {DA5AE0BA-E43D-4282-BC80-807DDE0C22C0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5AE8C9D7-2613-4E1A-A4F2-579BAC28D0A2} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.projitems*{b0e5e9cc-5fb4-4f94-bd54-115a91a6ae9d}*SharedItemsImports = 13 + Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.projitems*{e0c26d3a-504a-4826-bae2-de775f865b2a}*SharedItemsImports = 5 + EndGlobalSection EndGlobal From a883d78c5dcf78d57b2d20f76cc248430400399d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 18:40:37 -0800 Subject: [PATCH 17/40] Add shared .props for generators --- .../WinRT.SourceGenerator.Roslyn4080.csproj | 28 +------- .../WinRT.SourceGenerator.projitems | 1 + .../WinRT.SourceGenerator.props | 72 +++++++++++++++++++ src/Authoring/cswinmd/CsWinMD.csproj | 2 +- .../DiagnosticTests/DiagnosticTests.csproj | 2 +- .../SourceGeneratorTest.csproj | 2 +- 6 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj index a4dd37506..d0b0785bb 100644 --- a/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4080/WinRT.SourceGenerator.Roslyn4080.csproj @@ -1,32 +1,6 @@  - - netstandard2.0 - 11 - Microsoft Corporation - Microsoft Corporation - C#/WinRT - WinRT.SourceGenerator - $(VersionNumber) - $(VersionNumber) - $(VersionNumber) - $(VersionNumber) - en - C#/WinRT Authoring Source Generator Preview $(VersionString) - C#/WinRT Authoring Source Generator Preview v$(VersionString) - Copyright (c) Microsoft Corporation. All rights reserved. - true - $(SolutionDir)WinRT.Runtime\key.snk - true - true - - - - - - - - + diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems index f1350d2c0..8d568de02 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems @@ -9,6 +9,7 @@ WinRT.SourceGenerator + diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props new file mode 100644 index 000000000..f77d1e5a0 --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props @@ -0,0 +1,72 @@ + + + + netstandard2.0 + 12.0 + Microsoft Corporation + Microsoft Corporation + C#/WinRT + WinRT.SourceGenerator + $(VersionNumber) + $(VersionNumber) + $(VersionNumber) + $(VersionNumber) + en + C#/WinRT Authoring Source Generator Preview $(VersionString) + C#/WinRT Authoring Source Generator Preview v$(VersionString) + Copyright (c) Microsoft Corporation. All rights reserved. + true + $(SolutionDir)WinRT.Runtime\key.snk + true + true + + + embedded + + + + + + + $(MSBuildProjectName.Substring(0, $([MSBuild]::Subtract($(MSBuildProjectName.Length), 11)))) + + + $(MSBuildProjectName.Substring($([MSBuild]::Subtract($(MSBuildProjectName.Length), 4)), 1)) + $(MSBuildProjectName.Substring($([MSBuild]::Subtract($(MSBuildProjectName.Length), 3)), 2)) + $(MSBuildProjectName.Substring($([MSBuild]::Subtract($(MSBuildProjectName.Length), 1)), 1)) + $(CsWinRTSourceGeneratorRoslynMajorVersion).$(CsWinRTSourceGeneratorRoslynMinorVersion).$(CsWinRTSourceGeneratorRoslynPatchVersion) + + + $(DefineConstants);ROSLYN_4_8_0_OR_GREATER + $(DefineConstants);ROSLYN_4_12_0_OR_GREATER + + + $(NoWarn);RS2003 + + + 4.12.0-3.final + + + + + + + + \ No newline at end of file diff --git a/src/Authoring/cswinmd/CsWinMD.csproj b/src/Authoring/cswinmd/CsWinMD.csproj index a86d5081a..daec0f477 100644 --- a/src/Authoring/cswinmd/CsWinMD.csproj +++ b/src/Authoring/cswinmd/CsWinMD.csproj @@ -30,7 +30,7 @@ - + diff --git a/src/Tests/DiagnosticTests/DiagnosticTests.csproj b/src/Tests/DiagnosticTests/DiagnosticTests.csproj index 57333e536..ef4dc1ada 100644 --- a/src/Tests/DiagnosticTests/DiagnosticTests.csproj +++ b/src/Tests/DiagnosticTests/DiagnosticTests.csproj @@ -16,6 +16,6 @@ - + diff --git a/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj b/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj index 218108cf4..4156d5705 100644 --- a/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj +++ b/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj @@ -13,7 +13,7 @@ - + From b58d93de2e742e4fe94997414281205246b53811 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 18:48:56 -0800 Subject: [PATCH 18/40] Add Roslyn 4.12 version of the generators --- .../WinRT.SourceGenerator.Roslyn4120.csproj | 6 ++++++ .../WinRT.SourceGenerator/AotOptimizer.cs | 2 ++ .../CollectionExpressionAnalyzer.cs | 4 ++++ .../CollectionExpressionIDE0300Suppressor.cs | 4 ++++ .../CollectionExpressionIDE0303Suppressor.cs | 4 ++++ .../CollectionExpressionIDE0305Suppressor.cs | 4 ++++ .../CollectionExpressionSuppressor.cs | 4 ++++ .../CsWinRTDiagnosticStrings.Designer.cs | 2 +- .../WinRT.SourceGenerator.props | 4 +++- src/cswinrt.sln | 20 +++++++++++++++++++ 10 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/Authoring/WinRT.SourceGenerator.Roslyn4120/WinRT.SourceGenerator.Roslyn4120.csproj diff --git a/src/Authoring/WinRT.SourceGenerator.Roslyn4120/WinRT.SourceGenerator.Roslyn4120.csproj b/src/Authoring/WinRT.SourceGenerator.Roslyn4120/WinRT.SourceGenerator.Roslyn4120.csproj new file mode 100644 index 000000000..d0b0785bb --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator.Roslyn4120/WinRT.SourceGenerator.Roslyn4120.csproj @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs index e8957e9e7..a0814447c 100644 --- a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs +++ b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs @@ -1307,6 +1307,7 @@ private static EquatableArray GetVtableAttributesToAddOnLookupT } } } +#if ROSLYN_4_12_0_OR_GREATER else if (context.Node is CollectionExpressionSyntax collectionExpression) { // Detect collection expressions scenarios targeting interfaces, where we can rely on the concrete type @@ -1336,6 +1337,7 @@ SpecialType.System_Collections_Generic_IReadOnlyCollection_T or } } } +#endif return vtableAttributes.ToImmutableArray(); diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs index ae3aa1439..9ce2dc7a5 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if ROSLYN_4_12_0_OR_GREATER + using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis; using System.Collections.Immutable; @@ -70,3 +72,5 @@ SpecialType.System_Collections_Generic_ICollection_T or }); } } + +#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs index 146be1f6f..5fbff0dd2 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if ROSLYN_4_12_0_OR_GREATER + using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -78,3 +80,5 @@ SpecialType.System_Collections_Generic_IReadOnlyCollection_T or } } } + +#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs index aa64a5786..517764a98 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if ROSLYN_4_12_0_OR_GREATER + using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -40,3 +42,5 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) } } } + +#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs index 5cbf8c2d6..284657afe 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if ROSLYN_4_12_0_OR_GREATER + using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -71,3 +73,5 @@ SpecialType.System_Collections_Generic_IReadOnlyCollection_T or SpecialType.System_Collections_Generic_IReadOnlyList_T; } } + +#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs index e94469253..911460958 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if ROSLYN_4_12_0_OR_GREATER + using System; using System.Collections.Immutable; using Microsoft.CodeAnalysis; @@ -90,3 +92,5 @@ private static bool ShouldSuppressIDE0303OrIDE0304OrIDE0305(ICollectionExpressio return !GeneratorHelper.HasAttributeWithType(typeSymbol, collectionBuilderSymbol); } } + +#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs index 6e27f64f5..187ceaa17 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs +++ b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs @@ -39,7 +39,7 @@ internal CsWinRTDiagnosticStrings() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinRT.SourceGenerator.Roslyn4080.CsWinRTDiagnosticStrings", typeof(CsWinRTDiagnosticStrings).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinRT.SourceGenerator.CsWinRTDiagnosticStrings", typeof(CsWinRTDiagnosticStrings).Assembly); resourceMan = temp; } return resourceMan; diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props index f77d1e5a0..61384a1e2 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props @@ -37,6 +37,8 @@ supports analyzers that bundle multiple versions in the same NuGet package, each in a subfolder with a name matching the Roslyn version. To leverage this, we compute the 'CsWinRTSourceGeneratorRoslynVersion' property based on target project, so that the CsWinRT can build it multiple times with multiple versions during packing, to then extract each .dll and copy it to the right NuGet package folder. + + This setup and architecture for multi-targeting source generators is ported from https://github.com/CommunityToolkit/dotnet. --> @@ -65,7 +67,7 @@ - + diff --git a/src/cswinrt.sln b/src/cswinrt.sln index ed013a653..4abfb90b2 100644 --- a/src/cswinrt.sln +++ b/src/cswinrt.sln @@ -178,6 +178,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGeneratorTest", "Test EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "WinRT.SourceGenerator", "Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.shproj", "{B0E5E9CC-5FB4-4F94-BD54-115A91A6AE9D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinRT.SourceGenerator.Roslyn4120", "Authoring\WinRT.SourceGenerator.Roslyn4120\WinRT.SourceGenerator.Roslyn4120.csproj", "{20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -862,6 +864,22 @@ Global {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|x64.Build.0 = Release|Any CPU {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|x86.ActiveCfg = Release|Any CPU {CB7C338F-3850-4744-A1EA-3DC47B703C4A}.Release|x86.Build.0 = Release|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Debug|ARM.ActiveCfg = Debug|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Debug|ARM.Build.0 = Debug|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Debug|ARM64.Build.0 = Debug|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Debug|x64.ActiveCfg = Debug|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Debug|x64.Build.0 = Debug|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Debug|x86.ActiveCfg = Debug|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Debug|x86.Build.0 = Debug|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Release|ARM.ActiveCfg = Release|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Release|ARM.Build.0 = Release|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Release|ARM64.ActiveCfg = Release|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Release|ARM64.Build.0 = Release|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Release|x64.ActiveCfg = Release|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Release|x64.Build.0 = Release|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Release|x86.ActiveCfg = Release|Any CPU + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -916,11 +934,13 @@ Global {FFC0B06E-78E7-44D5-8E67-8FE5744CE071} = {5ECC38F0-16FD-47E1-B8DC-8C474008AD55} {CB7C338F-3850-4744-A1EA-3DC47B703C4A} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} {B0E5E9CC-5FB4-4F94-BD54-115A91A6AE9D} = {DA5AE0BA-E43D-4282-BC80-807DDE0C22C0} + {20F67B53-BDF2-4252-A0E1-6D0AB55BA2F9} = {DA5AE0BA-E43D-4282-BC80-807DDE0C22C0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5AE8C9D7-2613-4E1A-A4F2-579BAC28D0A2} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution + Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.projitems*{20f67b53-bdf2-4252-a0e1-6d0ab55ba2f9}*SharedItemsImports = 5 Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.projitems*{b0e5e9cc-5fb4-4f94-bd54-115a91a6ae9d}*SharedItemsImports = 13 Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.projitems*{e0c26d3a-504a-4826-bae2-de775f865b2a}*SharedItemsImports = 5 EndGlobalSection From 9e90d51fd297ca6425c60b455e614170afe657d1 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 20:14:49 -0800 Subject: [PATCH 19/40] Use 'Microsoft.CodeAnalysis.CSharp.Workspaces' --- src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props index 61384a1e2..98e3cc6cd 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.props @@ -67,7 +67,7 @@ - + From 002332bc8d27a65c3da4c027e0e034e5068a8d0b Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 22:49:15 -0800 Subject: [PATCH 20/40] Fix the diagnostic suppressors --- .../CollectionExpressionIDE0300Suppressor.cs | 2 +- .../CollectionExpressionIDE0305Suppressor.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs index 5fbff0dd2..0b6a51868 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs @@ -70,7 +70,7 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) // If the target type is either 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList', suppress the diagnostic. // This is because using a collection expression in this case would produce an opaque type we cannot analyze for marshalling. - if (typeSymbol.SpecialType is + if (typeSymbol.ConstructedFrom.SpecialType is SpecialType.System_Collections_Generic_IEnumerable_T or SpecialType.System_Collections_Generic_IReadOnlyCollection_T or SpecialType.System_Collections_Generic_IReadOnlyList_T) diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs index 284657afe..ebf52a18e 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs @@ -67,7 +67,7 @@ public static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAna // Like for 'IDE0300', suppress diagnostics for 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList' return - typeSymbol.SpecialType is + typeSymbol.ConstructedFrom.SpecialType is SpecialType.System_Collections_Generic_IEnumerable_T or SpecialType.System_Collections_Generic_IReadOnlyCollection_T or SpecialType.System_Collections_Generic_IReadOnlyList_T; From ca39b05323dc5b5e35af880be8a826d06fad8d33 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 22:49:50 -0800 Subject: [PATCH 21/40] Remove leftover file --- .../CollectionExpressionSuppressor.cs | 96 ------------------- .../WinRT.SourceGenerator.projitems | 1 - 2 files changed, 97 deletions(-) delete mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs deleted file mode 100644 index 911460958..000000000 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionSuppressor.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#if ROSLYN_4_12_0_OR_GREATER - -using System; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Operations; -using WinRT.SourceGenerator; - -#nullable enable - -namespace Generator; - -/// -/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. -/// -[DiagnosticAnalyzer(LanguageNames.CSharp)] -public sealed class CollectionExpressionSuppressor : DiagnosticSuppressor -{ - /// - public override ImmutableArray SupportedSuppressions { get; } = - [ - WinRTSuppressions.CollectionExpressionIDE0303, - WinRTSuppressions.CollectionExpressionIDE0304, - WinRTSuppressions.CollectionExpressionIDE0305 - ]; - - /// - public override void ReportSuppressions(SuppressionAnalysisContext context) - { - foreach (Diagnostic diagnostic in context.ReportedDiagnostics) - { - // Try to get the syntax node matching the location of the diagnostic - if (diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan) is not CollectionExpressionSyntax syntaxNode) - { - continue; - } - - // If the collection expression has no elements, we want to keep the diagnostic - if (!syntaxNode.Elements.Any()) - { - continue; - } - - SemanticModel semanticModel = context.GetSemanticModel(syntaxNode.SyntaxTree); - - // Try to get the operation for the collection expression, skip if we can't - if (semanticModel.GetOperation(syntaxNode, context.CancellationToken) is not ICollectionExpressionOperation operation) - { - continue; - } - - // Try to suppress all supported diagnostics - if (ShouldSuppressIDE0303OrIDE0304OrIDE0305(operation, semanticModel.Compilation)) - { - SuppressionDescriptor descriptor = diagnostic.Id switch - { - "IDE0303" => WinRTSuppressions.CollectionExpressionIDE0303, - "IDE0304" => WinRTSuppressions.CollectionExpressionIDE0304, - "IDE0305" => WinRTSuppressions.CollectionExpressionIDE0305, - _ => throw new Exception($"Unsupported diagnostic id: '{diagnostic.Id}'.") - }; - - context.ReportSuppression(Suppression.Create(descriptor, diagnostic)); - } - } - } - - /// - /// Checks whether 'IDE0303', 'IDE0304', or 'IDE0305' should be suppressed for a given operation. - /// - private static bool ShouldSuppressIDE0303OrIDE0304OrIDE0305(ICollectionExpressionOperation operation, Compilation compilation) - { - // We only possibly suppress here for some interface types - if (operation.Type is not INamedTypeSymbol { TypeKind: TypeKind.Interface } typeSymbol) - { - return false; - } - - // Get the symbol for '[CollectionBuilder]', we need it for lookups - if (compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.CollectionBuilderAttribute") is not { } collectionBuilderSymbol) - { - return false; - } - - // We should only suppress when the target interface does not have '[CollectionBuilder]' on it. - // If it does, then the CsWinRT analyzer will be able to analyze the body of the 'Create' method. - return !GeneratorHelper.HasAttributeWithType(typeSymbol, collectionBuilderSymbol); - } -} - -#endif diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems index 8d568de02..d5832b8a4 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems @@ -18,7 +18,6 @@ - CsWinRTDiagnosticStrings.resx True From ffaf2d2ec168b0fb477c391186a541468a0d2740 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 23:11:37 -0800 Subject: [PATCH 22/40] Rename analyzer test helper --- .../SourceGeneratorTest/DiagnosticAnalyzerTests.cs | 10 +++++----- ...{TAnalyzer}.cs => CSharpAnalyzerTest{TAnalyzer}.cs} | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) rename src/Tests/SourceGeneratorTest/Helpers/{CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs => CSharpAnalyzerTest{TAnalyzer}.cs} (83%) diff --git a/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs b/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs index 28fc1a484..770342727 100644 --- a/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs +++ b/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs @@ -26,7 +26,7 @@ void M() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -48,7 +48,7 @@ void M() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -71,7 +71,7 @@ void M(int x, IEnumerable y) } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -121,7 +121,7 @@ public static IMyInterface Create(ReadOnlySpan span) } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -147,6 +147,6 @@ void M(int x, IEnumerable y) } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } } \ No newline at end of file diff --git a/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs b/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs similarity index 83% rename from src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs rename to src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs index 42ba5b72f..294c68c33 100644 --- a/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs +++ b/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs @@ -14,7 +14,7 @@ namespace SourceGeneratorTest.Helpers; /// /// The type of the analyzer to test. // Ported from https://github.com/Sergio0694/ComputeSharp -internal sealed class CSharpAnalyzerWithLanguageVersionTest : CSharpAnalyzerTest +internal sealed class CSharpAnalyzerTest : CSharpAnalyzerTest where TAnalyzer : DiagnosticAnalyzer, new() { /// @@ -28,11 +28,11 @@ internal sealed class CSharpAnalyzerWithLanguageVersionTest : CSharpA private readonly LanguageVersion _languageVersion; /// - /// Creates a new instance with the specified paramaters. + /// Creates a new instance with the specified paramaters. /// /// Whether to enable unsafe blocks. /// The C# language version to use to parse code. - private CSharpAnalyzerWithLanguageVersionTest(bool allowUnsafeBlocks, LanguageVersion languageVersion) + private CSharpAnalyzerTest(bool allowUnsafeBlocks, LanguageVersion languageVersion) { _allowUnsafeBlocks = allowUnsafeBlocks; _languageVersion = languageVersion; @@ -59,7 +59,7 @@ public static Task VerifyAnalyzerAsync( bool allowUnsafeBlocks = true, LanguageVersion languageVersion = LanguageVersion.CSharp12) { - CSharpAnalyzerWithLanguageVersionTest test = new(allowUnsafeBlocks, languageVersion) { TestCode = source }; + CSharpAnalyzerTest test = new(allowUnsafeBlocks, languageVersion) { TestCode = source }; test.TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net80; test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(ComWrappersSupport).Assembly.Location)); From a84a0f8da5bb9d28782eb23a194ca5470c17a021 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 23:12:15 -0800 Subject: [PATCH 23/40] Add 'CSharpSuppressorTest' type --- .../CSharpSuppressorTest{TSuppressor}.cs | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs diff --git a/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs b/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs new file mode 100644 index 000000000..844faea85 --- /dev/null +++ b/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs @@ -0,0 +1,150 @@ +using System.Collections.Generic; +using System; +using System.Collections.Immutable; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using WinRT; +using Microsoft.CodeAnalysis.CSharp; + +namespace SourceGeneratorTest.Helpers; + +/// +/// A custom for testing diagnostic suppressors. +/// +/// The type of the suppressor to test. +// Adapted from https://github.com/ImmediatePlatform/Immediate.Validations +public sealed class CSharpSuppressorTest : CSharpAnalyzerTest + where TSuppressor : DiagnosticSuppressor, new() +{ + /// + /// The list of analyzers to run on the input code. + /// + private readonly List _analyzers = []; + + /// + /// Whether to enable unsafe blocks. + /// + private readonly bool _allowUnsafeBlocks; + + /// + /// The C# language version to use to parse code. + /// + private readonly LanguageVersion _languageVersion; + + /// + /// Creates a new instance with the specified parameters. + /// + /// The source code to analyze. + /// Whether to enable unsafe blocks. + /// The language version to use to run the test. + public CSharpSuppressorTest( + string source, + bool allowUnsafeBlocks = true, + LanguageVersion languageVersion = LanguageVersion.CSharp12) + { + _allowUnsafeBlocks = allowUnsafeBlocks; + _languageVersion = languageVersion; + + TestCode = source; + TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net80; + TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(ComWrappersSupport).Assembly.Location)); + } + + /// + protected override IEnumerable GetDiagnosticAnalyzers() + { + return base.GetDiagnosticAnalyzers().Concat(_analyzers); + } + + /// + protected override CompilationOptions CreateCompilationOptions() + { + return new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: _allowUnsafeBlocks); + } + + /// + protected override ParseOptions CreateParseOptions() + { + return new CSharpParseOptions(_languageVersion, DocumentationMode.Diagnose); + } + + /// + /// Adds a new analyzer to the set of analyzers to run on the input code. + /// + /// The type of analyzer to activate. + /// The current test instance. + public CSharpSuppressorTest WithAnalyzer( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] string assemblyQualifiedTypeName) + { + _analyzers.Add((DiagnosticAnalyzer)Activator.CreateInstance(Type.GetType(assemblyQualifiedTypeName))); + + return this; + } + + /// + /// Specifies the diagnostics to enable. + /// + /// The set of diagnostics. + /// The current test instance. + public CSharpSuppressorTest WithSpecificDiagnostics(params DiagnosticResult[] diagnostics) + { + ImmutableDictionary diagnosticOptions = diagnostics.ToImmutableDictionary( + descriptor => descriptor.Id, + descriptor => descriptor.Severity.ToReportDiagnostic()); + + // Transform to enable the diagnostics + Solution EnableDiagnostics(Solution solution, ProjectId projectId) + { + CompilationOptions options = + solution.GetProject(projectId)?.CompilationOptions + ?? throw new InvalidOperationException("Compilation options missing."); + + return solution.WithProjectCompilationOptions( + projectId, + options.WithSpecificDiagnosticOptions(diagnosticOptions)); + } + + SolutionTransforms.Clear(); + SolutionTransforms.Add(EnableDiagnostics); + + return this; + } + + /// + /// Specifies the diagnostics that should be produced. + /// + /// The set of diagnostics. + /// The current test instance. + public CSharpSuppressorTest WithExpectedDiagnosticsResults(params DiagnosticResult[] diagnostics) + { + ExpectedDiagnostics.AddRange(diagnostics); + + return this; + } +} + +/// +/// Extensions for . +/// +file static class DiagnosticSeverityExtensions +{ + /// + /// Converts a value into a one. + /// + public static ReportDiagnostic ToReportDiagnostic(this DiagnosticSeverity severity) + { + return severity switch + { + DiagnosticSeverity.Hidden => ReportDiagnostic.Hidden, + DiagnosticSeverity.Info => ReportDiagnostic.Info, + DiagnosticSeverity.Warning => ReportDiagnostic.Warn, + DiagnosticSeverity.Error => ReportDiagnostic.Error, + _ => throw new InvalidEnumArgumentException(nameof(severity), (int)severity, typeof(DiagnosticSeverity)), + }; + } +} \ No newline at end of file From 0ddb2c13d7e6a1eaf1ddb9d5b26234e2c247118a Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 24 Nov 2024 23:13:23 -0800 Subject: [PATCH 24/40] Add 'DiagnosticSuppressorTests' --- .../DiagnosticSuppressorTests.cs | 35 +++++++++++++++++++ .../SourceGeneratorTest.csproj | 11 ++++-- 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs diff --git a/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs b/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs new file mode 100644 index 000000000..050bd94e2 --- /dev/null +++ b/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using Generator; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SourceGeneratorTest.Helpers; + +namespace SourceGeneratorTest; + +[TestClass] +public sealed class DiagnosticSuppressorTests +{ + public static readonly DiagnosticResult IDE0300 = DiagnosticResult.CompilerWarning("IDE0300"); + + [TestMethod] + public async Task CollectionExpression_IDE0300_ArrayInitializer_TargetingArray_NotSuppressed() + { + await new CSharpSuppressorTest( + """ + class TestClass + { + private int[] f = {|IDE0300:{|} 1, 2, 3 }; + + void TestMethod() + { + int[] a = {|IDE0300:{|} 1, 2, 3 }; + } + + public int[] P { get; } = {|IDE0300:{|} 1, 2, 3 }; + } + """) + .WithAnalyzer("Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer, Microsoft.CodeAnalysis.CSharp.CodeStyle") + .WithSpecificDiagnostics(IDE0300) + .RunAsync(); + } +} \ No newline at end of file diff --git a/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj b/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj index 4156d5705..931947ccf 100644 --- a/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj +++ b/src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj @@ -9,11 +9,18 @@ - + + - + + + + + + + From 056b52e2f56839dee265aed19b2778d544be11e1 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 25 Nov 2024 08:47:54 -0800 Subject: [PATCH 25/40] Skip new analyzers if not in 'auto' mode --- .../CollectionExpressions/CollectionExpressionAnalyzer.cs | 6 ++++++ .../CollectionExpressionIDE0300Suppressor.cs | 6 ++++++ .../CollectionExpressionIDE0303Suppressor.cs | 6 ++++++ .../CollectionExpressionIDE0305Suppressor.cs | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs index 9ce2dc7a5..f91426789 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs @@ -30,6 +30,12 @@ public override void Initialize(AnalysisContext context) context.RegisterCompilationStartAction(static context => { + // We only need to emit warnings if CsWinRT is in 'auto' mode + if (!GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation)) + { + return; + } + // Get the symbol for '[CollectionBuilder]', we need it for lookups if (context.Compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.CollectionBuilderAttribute") is not { } collectionBuilderSymbol) { diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs index 0b6a51868..9ad8dbd93 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs @@ -36,6 +36,12 @@ public sealed class CollectionExpressionIDE0300Suppressor : DiagnosticSuppressor /// public override void ReportSuppressions(SuppressionAnalysisContext context) { + // Skip the logic if CsWinRT is not in 'auto' mode + if (!GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation)) + { + return; + } + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) { // Try to get the syntax node matching the location of the diagnostic diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs index 517764a98..74644cddc 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs @@ -33,6 +33,12 @@ public sealed class CollectionExpressionIDE0303Suppressor : DiagnosticSuppressor /// public override void ReportSuppressions(SuppressionAnalysisContext context) { + // Skip the logic if CsWinRT is not in 'auto' mode + if (!GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation)) + { + return; + } + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) { if (CollectionExpressionIDE0305Suppressor.IsInvocationAssignedToUnsupportedInterfaceType(context, diagnostic)) diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs index ebf52a18e..6d5c75996 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs @@ -34,6 +34,12 @@ public sealed class CollectionExpressionIDE0305Suppressor : DiagnosticSuppressor /// public override void ReportSuppressions(SuppressionAnalysisContext context) { + // Skip the logic if CsWinRT is not in 'auto' mode + if (!GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation)) + { + return; + } + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) { if (IsInvocationAssignedToUnsupportedInterfaceType(context, diagnostic)) From f8e9bf27aa63e51452c6dbc6177596c33bafc328 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 25 Nov 2024 09:24:04 -0800 Subject: [PATCH 26/40] Update project references to generators --- src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj | 2 +- src/Projections/Windows/Windows.csproj | 2 +- src/Tests/AuthoringTest/AuthoringTest.csproj | 2 +- src/Tests/AuthoringWuxTest/AuthoringWuxTest.csproj | 2 +- src/Tests/FunctionalTests/Async/Async.csproj | 2 +- src/Tests/FunctionalTests/CCW/CCW.csproj | 2 +- .../FunctionalTests/ClassActivation/ClassActivation.csproj | 2 +- src/Tests/FunctionalTests/Collections/Collections.csproj | 2 +- .../DerivedClassActivation/DerivedClassActivation.csproj | 2 +- .../DerivedClassAsBaseClass/DerivedClassAsBaseClass.csproj | 4 ++-- .../DynamicInterfaceCasting/DynamicInterfaceCasting.csproj | 2 +- src/Tests/FunctionalTests/Events/Events.csproj | 2 +- .../JsonValueFunctionCalls/JsonValueFunctionCalls.csproj | 2 +- src/Tests/FunctionalTests/NonWinRT/NonWinRT.csproj | 2 +- src/Tests/FunctionalTests/OptInMode/OptInMode.csproj | 2 +- src/Tests/FunctionalTests/Structs/Structs.csproj | 2 +- .../TestImplementExclusiveTo/TestImplementExclusiveTo.csproj | 2 +- src/Tests/FunctionalTests/TestLibrary/Test-Library.csproj | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj b/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj index be08e87f7..5c422987f 100644 --- a/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj +++ b/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/Projections/Windows/Windows.csproj b/src/Projections/Windows/Windows.csproj index 3dde59ba7..c0eb946a5 100644 --- a/src/Projections/Windows/Windows.csproj +++ b/src/Projections/Windows/Windows.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/Tests/AuthoringTest/AuthoringTest.csproj b/src/Tests/AuthoringTest/AuthoringTest.csproj index e1cdfc454..0e31235a1 100644 --- a/src/Tests/AuthoringTest/AuthoringTest.csproj +++ b/src/Tests/AuthoringTest/AuthoringTest.csproj @@ -37,7 +37,7 @@ - + diff --git a/src/Tests/AuthoringWuxTest/AuthoringWuxTest.csproj b/src/Tests/AuthoringWuxTest/AuthoringWuxTest.csproj index e754706b9..d7eb510ef 100644 --- a/src/Tests/AuthoringWuxTest/AuthoringWuxTest.csproj +++ b/src/Tests/AuthoringWuxTest/AuthoringWuxTest.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/Tests/FunctionalTests/Async/Async.csproj b/src/Tests/FunctionalTests/Async/Async.csproj index 420191949..812581cc3 100644 --- a/src/Tests/FunctionalTests/Async/Async.csproj +++ b/src/Tests/FunctionalTests/Async/Async.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tests/FunctionalTests/CCW/CCW.csproj b/src/Tests/FunctionalTests/CCW/CCW.csproj index c7fe45f74..4a4b75519 100644 --- a/src/Tests/FunctionalTests/CCW/CCW.csproj +++ b/src/Tests/FunctionalTests/CCW/CCW.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Tests/FunctionalTests/ClassActivation/ClassActivation.csproj b/src/Tests/FunctionalTests/ClassActivation/ClassActivation.csproj index 420191949..3dfd13d96 100644 --- a/src/Tests/FunctionalTests/ClassActivation/ClassActivation.csproj +++ b/src/Tests/FunctionalTests/ClassActivation/ClassActivation.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tests/FunctionalTests/Collections/Collections.csproj b/src/Tests/FunctionalTests/Collections/Collections.csproj index 98495ff99..c961879d7 100644 --- a/src/Tests/FunctionalTests/Collections/Collections.csproj +++ b/src/Tests/FunctionalTests/Collections/Collections.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tests/FunctionalTests/DerivedClassActivation/DerivedClassActivation.csproj b/src/Tests/FunctionalTests/DerivedClassActivation/DerivedClassActivation.csproj index 7f0423881..f65cc8b91 100644 --- a/src/Tests/FunctionalTests/DerivedClassActivation/DerivedClassActivation.csproj +++ b/src/Tests/FunctionalTests/DerivedClassActivation/DerivedClassActivation.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tests/FunctionalTests/DerivedClassAsBaseClass/DerivedClassAsBaseClass.csproj b/src/Tests/FunctionalTests/DerivedClassAsBaseClass/DerivedClassAsBaseClass.csproj index 4200014b4..812581cc3 100644 --- a/src/Tests/FunctionalTests/DerivedClassAsBaseClass/DerivedClassAsBaseClass.csproj +++ b/src/Tests/FunctionalTests/DerivedClassAsBaseClass/DerivedClassAsBaseClass.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/src/Tests/FunctionalTests/DynamicInterfaceCasting/DynamicInterfaceCasting.csproj b/src/Tests/FunctionalTests/DynamicInterfaceCasting/DynamicInterfaceCasting.csproj index 4db5916f4..3c23f59b4 100644 --- a/src/Tests/FunctionalTests/DynamicInterfaceCasting/DynamicInterfaceCasting.csproj +++ b/src/Tests/FunctionalTests/DynamicInterfaceCasting/DynamicInterfaceCasting.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Tests/FunctionalTests/Events/Events.csproj b/src/Tests/FunctionalTests/Events/Events.csproj index 420191949..812581cc3 100644 --- a/src/Tests/FunctionalTests/Events/Events.csproj +++ b/src/Tests/FunctionalTests/Events/Events.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tests/FunctionalTests/JsonValueFunctionCalls/JsonValueFunctionCalls.csproj b/src/Tests/FunctionalTests/JsonValueFunctionCalls/JsonValueFunctionCalls.csproj index 7f0423881..f65cc8b91 100644 --- a/src/Tests/FunctionalTests/JsonValueFunctionCalls/JsonValueFunctionCalls.csproj +++ b/src/Tests/FunctionalTests/JsonValueFunctionCalls/JsonValueFunctionCalls.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tests/FunctionalTests/NonWinRT/NonWinRT.csproj b/src/Tests/FunctionalTests/NonWinRT/NonWinRT.csproj index 21513321e..48e6d2d54 100644 --- a/src/Tests/FunctionalTests/NonWinRT/NonWinRT.csproj +++ b/src/Tests/FunctionalTests/NonWinRT/NonWinRT.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Tests/FunctionalTests/OptInMode/OptInMode.csproj b/src/Tests/FunctionalTests/OptInMode/OptInMode.csproj index 69c29358a..a0b84d659 100644 --- a/src/Tests/FunctionalTests/OptInMode/OptInMode.csproj +++ b/src/Tests/FunctionalTests/OptInMode/OptInMode.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Tests/FunctionalTests/Structs/Structs.csproj b/src/Tests/FunctionalTests/Structs/Structs.csproj index 7f0423881..f65cc8b91 100644 --- a/src/Tests/FunctionalTests/Structs/Structs.csproj +++ b/src/Tests/FunctionalTests/Structs/Structs.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tests/FunctionalTests/TestImplementExclusiveTo/TestImplementExclusiveTo.csproj b/src/Tests/FunctionalTests/TestImplementExclusiveTo/TestImplementExclusiveTo.csproj index 2d2be4148..3e4ee3ef3 100644 --- a/src/Tests/FunctionalTests/TestImplementExclusiveTo/TestImplementExclusiveTo.csproj +++ b/src/Tests/FunctionalTests/TestImplementExclusiveTo/TestImplementExclusiveTo.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Tests/FunctionalTests/TestLibrary/Test-Library.csproj b/src/Tests/FunctionalTests/TestLibrary/Test-Library.csproj index f4fd0c44a..eae541591 100644 --- a/src/Tests/FunctionalTests/TestLibrary/Test-Library.csproj +++ b/src/Tests/FunctionalTests/TestLibrary/Test-Library.csproj @@ -7,7 +7,7 @@ - + From 8a14d399a021b7d20fd0000e8f1e5223e0e863b0 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 25 Nov 2024 09:45:45 -0800 Subject: [PATCH 27/40] Update build steps --- .../CsWinRT-Build-Steps.yml | 17 ++++++++++++++--- .../CsWinRT-PublishToNuget-Stage.yml | 7 ++++--- nuget/Microsoft.Windows.CsWinMD.nuspec | 2 +- nuget/Microsoft.Windows.CsWinRT.nuspec | 3 ++- src/build.cmd | 7 ++++--- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml index 9ff4a279f..f5f1350b0 100644 --- a/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml @@ -265,16 +265,27 @@ steps: WinRT.Runtime.pdb TargetFolder: $(Build.ArtifactStagingDirectory)\release_netstandard2.0\ -# Stage Source Generator +# Stage Source Generator (Roslyn 4.8) - task: CopyFiles@2 displayName: Stage Source Generator condition: and(succeeded(), eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildConfiguration'], 'release')) inputs: - SourceFolder: $(Build.SourcesDirectory)\src\Authoring\WinRT.SourceGenerator\bin\$(BuildConfiguration)\netstandard2.0 + SourceFolder: $(Build.SourcesDirectory)\src\Authoring\WinRT.SourceGenerator.Roslyn4080\bin\$(BuildConfiguration)\netstandard2.0 Contents: | WinRT.SourceGenerator.dll WinRT.SourceGenerator.pdb - TargetFolder: $(Build.ArtifactStagingDirectory)\release_netstandard2.0\ + TargetFolder: $(Build.ArtifactStagingDirectory)\release_netstandard2.0\roslyn4080\ + +# Stage Source Generator (Roslyn 4.12) +- task: CopyFiles@2 + displayName: Stage Source Generator + condition: and(succeeded(), eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildConfiguration'], 'release')) + inputs: + SourceFolder: $(Build.SourcesDirectory)\src\Authoring\WinRT.SourceGenerator.Roslyn4120\bin\$(BuildConfiguration)\netstandard2.0 + Contents: | + WinRT.SourceGenerator.dll + WinRT.SourceGenerator.pdb + TargetFolder: $(Build.ArtifactStagingDirectory)\release_netstandard2.0\roslyn4120\ # Stage Net8.0 - task: CopyFiles@2 diff --git a/build/AzurePipelineTemplates/CsWinRT-PublishToNuget-Stage.yml b/build/AzurePipelineTemplates/CsWinRT-PublishToNuget-Stage.yml index fb692d7c5..2a011f5f9 100644 --- a/build/AzurePipelineTemplates/CsWinRT-PublishToNuget-Stage.yml +++ b/build/AzurePipelineTemplates/CsWinRT-PublishToNuget-Stage.yml @@ -90,7 +90,8 @@ stages: WinRT.Interop.winmd netstandard2.0\WinRT.Runtime.dll netstandard2.0\WinRT.Host.Shim.dll - netstandard2.0\WinRT.SourceGenerator.dll + netstandard2.0\roslyn4080\WinRT.SourceGenerator.dll + netstandard2.0\roslyn4120\WinRT.SourceGenerator.dll net8.0\WinRT.Host.Shim.dll net8.0\WinRT.Runtime.dll release_x64\WinRT.Host.dll @@ -221,7 +222,7 @@ stages: command: pack searchPatternPack: nuget/Microsoft.Windows.CsWinRT.nuspec configurationToPack: Release - buildProperties: cswinrt_nuget_version=$(NugetVersion);cswinrt_exe=$(Build.SourcesDirectory)\cswinrt.exe;interop_winmd=$(Build.SourcesDirectory)\WinRT.Interop.winmd;netstandard2_runtime=$(Build.SourcesDirectory)\netstandard2.0\WinRT.Runtime.dll;net8_runtime=$(Build.SourcesDirectory)\net8.0\WinRT.Runtime.dll;source_generator=$(Build.SourcesDirectory)\netstandard2.0\WinRT.SourceGenerator.dll;winrt_shim=$(Build.SourcesDirectory)\net8.0\WinRT.Host.Shim.dll;winrt_host_x86=$(Build.SourcesDirectory)\release_x86\WinRT.Host.dll;winrt_host_x64=$(Build.SourcesDirectory)\release_x64\WinRT.Host.dll;winrt_host_arm64=$(Build.SourcesDirectory)\release_arm64\WinRT.Host.dll;winrt_host_resource_x86=$(Build.SourcesDirectory)\release_x86\WinRT.Host.dll.mui;winrt_host_resource_x64=$(Build.SourcesDirectory)\release_x64\WinRT.Host.dll.mui;winrt_host_resource_arm64=$(Build.SourcesDirectory)\release_arm64\WinRT.Host.dll.mui;guid_patch=$(Build.SourcesDirectory)\net8.0\IIDOptimizer\*.* + buildProperties: cswinrt_nuget_version=$(NugetVersion);cswinrt_exe=$(Build.SourcesDirectory)\cswinrt.exe;interop_winmd=$(Build.SourcesDirectory)\WinRT.Interop.winmd;netstandard2_runtime=$(Build.SourcesDirectory)\netstandard2.0\WinRT.Runtime.dll;net8_runtime=$(Build.SourcesDirectory)\net8.0\WinRT.Runtime.dll;source_generator_roslyn4080=$(Build.SourcesDirectory)\netstandard2.0\roslyn4080\WinRT.SourceGenerator.dll;source_generator_roslyn4120=$(Build.SourcesDirectory)\netstandard2.0\roslyn4120\WinRT.SourceGenerator.dll;winrt_shim=$(Build.SourcesDirectory)\net8.0\WinRT.Host.Shim.dll;winrt_host_x86=$(Build.SourcesDirectory)\release_x86\WinRT.Host.dll;winrt_host_x64=$(Build.SourcesDirectory)\release_x64\WinRT.Host.dll;winrt_host_arm64=$(Build.SourcesDirectory)\release_arm64\WinRT.Host.dll;winrt_host_resource_x86=$(Build.SourcesDirectory)\release_x86\WinRT.Host.dll.mui;winrt_host_resource_x64=$(Build.SourcesDirectory)\release_x64\WinRT.Host.dll.mui;winrt_host_resource_arm64=$(Build.SourcesDirectory)\release_arm64\WinRT.Host.dll.mui;guid_patch=$(Build.SourcesDirectory)\net8.0\IIDOptimizer\*.* - task: NuGetCommand@2 displayName: NuGet pack @@ -230,7 +231,7 @@ stages: command: pack searchPatternPack: nuget/Microsoft.Windows.CsWinMD.nuspec configurationToPack: Release - buildProperties: cswinmd_nuget_version=$(NugetVersion);cswinmd_outpath=$(Build.SourcesDirectory)\net8.0\CsWinMD;source_generator=$(Build.SourcesDirectory)\netstandard2.0\WinRT.SourceGenerator.dll + buildProperties: cswinmd_nuget_version=$(NugetVersion);cswinmd_outpath=$(Build.SourcesDirectory)\net8.0\CsWinMD;source_generator_roslyn4080=$(Build.SourcesDirectory)\netstandard2.0\roslyn4080\WinRT.SourceGenerator.dll # ESRP CodeSigning - task: EsrpCodeSigning@5 diff --git a/nuget/Microsoft.Windows.CsWinMD.nuspec b/nuget/Microsoft.Windows.CsWinMD.nuspec index 19ad426b2..b28502c55 100644 --- a/nuget/Microsoft.Windows.CsWinMD.nuspec +++ b/nuget/Microsoft.Windows.CsWinMD.nuspec @@ -27,7 +27,7 @@ - + diff --git a/nuget/Microsoft.Windows.CsWinRT.nuspec b/nuget/Microsoft.Windows.CsWinRT.nuspec index d4c2c67ea..676cb6a40 100644 --- a/nuget/Microsoft.Windows.CsWinRT.nuspec +++ b/nuget/Microsoft.Windows.CsWinRT.nuspec @@ -31,7 +31,8 @@ - + + diff --git a/src/build.cmd b/src/build.cmd index ef72a2d9f..1869e6de4 100644 --- a/src/build.cmd +++ b/src/build.cmd @@ -339,7 +339,8 @@ set cswinrt_exe=%cswinrt_bin_dir%cswinrt.exe set interop_winmd=%cswinrt_bin_dir%WinRT.Interop.winmd set netstandard2_runtime=%this_dir%WinRT.Runtime\bin\%cswinrt_configuration%\netstandard2.0\WinRT.Runtime.dll set net8_runtime=%this_dir%WinRT.Runtime\bin\%cswinrt_configuration%\net8.0\WinRT.Runtime.dll -set source_generator=%this_dir%Authoring\WinRT.SourceGenerator\bin\%cswinrt_configuration%\netstandard2.0\WinRT.SourceGenerator.dll +set source_generator_roslyn4080=%this_dir%Authoring\WinRT.SourceGenerator.Roslyn4080\bin\%cswinrt_configuration%\netstandard2.0\WinRT.SourceGenerator.dll +set source_generator_roslyn4120=%this_dir%Authoring\WinRT.SourceGenerator.Roslyn4120\bin\%cswinrt_configuration%\netstandard2.0\WinRT.SourceGenerator.dll set winrt_host_%cswinrt_platform%=%this_dir%_build\%cswinrt_platform%\%cswinrt_configuration%\WinRT.Host\bin\WinRT.Host.dll set winrt_host_resource_%cswinrt_platform%=%this_dir%_build\%cswinrt_platform%\%cswinrt_configuration%\WinRT.Host\bin\WinRT.Host.dll.mui set winrt_shim=%this_dir%Authoring\WinRT.Host.Shim\bin\%cswinrt_configuration%\net8.0\WinRT.Host.Shim.dll @@ -347,8 +348,8 @@ set guid_patch=%this_dir%Perf\IIDOptimizer\bin\%cswinrt_configuration%\net8.0\*. set cswinmd_outpath=%this_dir%Authoring\cswinmd\bin\%cswinrt_configuration%\net8.0 rem Now call pack echo Creating nuget package -call :exec %nuget_dir%\nuget pack %this_dir%..\nuget\Microsoft.Windows.CsWinRT.nuspec -Properties cswinrt_exe=%cswinrt_exe%;interop_winmd=%interop_winmd%;netstandard2_runtime=%netstandard2_runtime%;net8_runtime=%net8_runtime%;source_generator=%source_generator%;cswinrt_nuget_version=%cswinrt_version_string%;winrt_host_x86=%winrt_host_x86%;winrt_host_x64=%winrt_host_x64%;winrt_host_arm=%winrt_host_arm%;winrt_host_arm64=%winrt_host_arm64%;winrt_host_resource_x86=%winrt_host_resource_x86%;winrt_host_resource_x64=%winrt_host_resource_x64%;winrt_host_resource_arm=%winrt_host_resource_arm%;winrt_host_resource_arm64=%winrt_host_resource_arm64%;winrt_shim=%winrt_shim%;guid_patch=%guid_patch% -OutputDirectory %cswinrt_bin_dir% -NonInteractive -Verbosity Detailed -NoPackageAnalysis -call :exec %nuget_dir%\nuget pack %this_dir%..\nuget\Microsoft.Windows.CsWinMD.nuspec -Properties cswinmd_outpath=%cswinmd_outpath%;source_generator=%source_generator%;cswinmd_nuget_version=%cswinrt_version_string%; -OutputDirectory %cswinrt_bin_dir% -NonInteractive -Verbosity Detailed -NoPackageAnalysis +call :exec %nuget_dir%\nuget pack %this_dir%..\nuget\Microsoft.Windows.CsWinRT.nuspec -Properties cswinrt_exe=%cswinrt_exe%;interop_winmd=%interop_winmd%;netstandard2_runtime=%netstandard2_runtime%;net8_runtime=%net8_runtime%;source_generator_roslyn4080=%source_generator_roslyn4080%;source_generator_roslyn4120=%source_generator_roslyn4120%;cswinrt_nuget_version=%cswinrt_version_string%;winrt_host_x86=%winrt_host_x86%;winrt_host_x64=%winrt_host_x64%;winrt_host_arm=%winrt_host_arm%;winrt_host_arm64=%winrt_host_arm64%;winrt_host_resource_x86=%winrt_host_resource_x86%;winrt_host_resource_x64=%winrt_host_resource_x64%;winrt_host_resource_arm=%winrt_host_resource_arm%;winrt_host_resource_arm64=%winrt_host_resource_arm64%;winrt_shim=%winrt_shim%;guid_patch=%guid_patch% -OutputDirectory %cswinrt_bin_dir% -NonInteractive -Verbosity Detailed -NoPackageAnalysis +call :exec %nuget_dir%\nuget pack %this_dir%..\nuget\Microsoft.Windows.CsWinMD.nuspec -Properties cswinmd_outpath=%cswinmd_outpath%;source_generator_roslyn4080=%source_generator_roslyn4080%;cswinmd_nuget_version=%cswinrt_version_string%; -OutputDirectory %cswinrt_bin_dir% -NonInteractive -Verbosity Detailed -NoPackageAnalysis goto :eof :exec From a89ce8aac70eaf2259ef87ef79928653d63e1bb7 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 25 Nov 2024 16:16:31 -0800 Subject: [PATCH 28/40] Change analyzer rule identifier --- .../AnalyzerReleases.Shipped.md | 2 +- .../WinRT.SourceGenerator/WinRTRules.cs | 2 +- .../DiagnosticAnalyzerTests.cs | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md b/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md index d835af3e5..bc133b788 100644 --- a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md +++ b/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md @@ -54,4 +54,4 @@ CsWinRT1030 | Usage | Warning | Project needs to be updated with ` y) { - IEnumerable a = {|CsWinRT1031:[1, 2, 3]|}; - IEnumerable b = {|CsWinRT1031:[x]|}; - IEnumerable c = {|CsWinRT1031:[1, x, ..y]|}; - IReadOnlyCollection d = {|CsWinRT1031:[1, 2, 3]|}; - IReadOnlyCollection e = {|CsWinRT1031:[x]|}; - IReadOnlyCollection f = {|CsWinRT1031:[1, x, ..y]|}; - IReadOnlyList g = {|CsWinRT1031:[1, 2, 3]|}; - IReadOnlyList h = {|CsWinRT1031:[x]|}; - IReadOnlyList i = {|CsWinRT1031:[1, x, ..y]|}; + IEnumerable a = {|CsWinRT1032:[1, 2, 3]|}; + IEnumerable b = {|CsWinRT1032:[x]|}; + IEnumerable c = {|CsWinRT1032:[1, x, ..y]|}; + IReadOnlyCollection d = {|CsWinRT1032:[1, 2, 3]|}; + IReadOnlyCollection e = {|CsWinRT1032:[x]|}; + IReadOnlyCollection f = {|CsWinRT1032:[1, x, ..y]|}; + IReadOnlyList g = {|CsWinRT1032:[1, 2, 3]|}; + IReadOnlyList h = {|CsWinRT1032:[x]|}; + IReadOnlyList i = {|CsWinRT1032:[1, x, ..y]|}; } } """; From eec6e3d10d5637afba6dc28ad29c5ac576d8ed8c Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 25 Nov 2024 16:30:21 -0800 Subject: [PATCH 29/40] Override resource names --- .../WinRT.SourceGenerator.projitems | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems index d5832b8a4..834e19625 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems @@ -43,17 +43,18 @@ CsWinRTDiagnosticStrings.Designer.cs ResXFileCodeGenerator + WinRT.SourceGenerator.CsWinRTDiagnosticStrings.resources - - - - - - - - - - + + + + + + + + + + From 1c4db638f3828b654c50c13859a241e3fe22ae94 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 25 Nov 2024 17:19:07 -0800 Subject: [PATCH 30/40] Only run source generator tests on x86 --- build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml b/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml index 599bf2516..05af30b83 100644 --- a/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml +++ b/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml @@ -65,11 +65,11 @@ stages: # Run Source Generator Tests - task: DotNetCoreCLI@2 displayName: Run Source Generator Tests - condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'))) + condition: and(succeeded(), eq(variables['BuildPlatform'], 'x86')) inputs: command: test projects: 'src/Tests/SourceGeneratorTest/SourceGeneratorTest.csproj' - arguments: --diag $(Build.ArtifactStagingDirectory)\unittest\test.log --no-build --logger trx;LogFilePath=UNITTEST-$(Build.BuildNumber).trx /nologo /m /p:platform=$(BuildPlatform);configuration=$(BuildConfiguration);CIBuildReason=CI -- RunConfiguration.TreatNoTestsAsError=true + arguments: --diag $(Build.ArtifactStagingDirectory)\unittest\test.log --no-build --logger trx;LogFilePath=UNITTEST-$(Build.BuildNumber).trx /nologo /m /p:configuration=$(BuildConfiguration);CIBuildReason=CI -- RunConfiguration.TreatNoTestsAsError=true testRunTitle: Unit Tests # Run Embedded Unit Tests From ada9f6639541666703626542d793ff1e614936d1 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 25 Nov 2024 19:02:36 -0800 Subject: [PATCH 31/40] Add 'CollectionExpressionIDE0304Suppressor' --- .../CollectionExpressionIDE0304Suppressor.cs | 64 +++++++++++++++++++ .../CollectionExpressionIDE0305Suppressor.cs | 9 +++ .../WinRT.SourceGenerator.projitems | 1 + 3 files changed, 74 insertions(+) create mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs new file mode 100644 index 000000000..7ecf26d5a --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#if ROSLYN_4_12_0_OR_GREATER + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using WinRT.SourceGenerator; + +#nullable enable + +namespace Generator; + +/// +/// +/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. +/// +/// +/// This analyzer suppress diagnostics for cases like these: +/// +/// var builder = ImmutableArray.CreateBuilder(); +/// builder.Add(1); +/// builder.AddRange(new int[] { 5, 6, 7 }); +/// ImmutableArray i = builder.ToImmutable(); +/// +/// +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class CollectionExpressionIDE0304Suppressor : DiagnosticSuppressor +{ + /// + public override ImmutableArray SupportedSuppressions { get; } = [WinRTSuppressions.CollectionExpressionIDE0304]; + + /// + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + // Skip the logic if CsWinRT is not in 'auto' mode + if (!GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation)) + { + return; + } + + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) + { + // The 'IDE0304' analyzer will add the location of the invocation expression in the additional locations set + if (diagnostic.AdditionalLocations is not [{ } invocationLocation, ..]) + { + continue; + } + + // Check the target invocation. The only thing we care about for this warning is whether the final invocation + // was being assigned to a concrete type (which is supported), or to a readonly interface type (which isn't). + SyntaxNode? syntaxNode = invocationLocation.SourceTree?.GetRoot(context.CancellationToken).FindNode(invocationLocation.SourceSpan); + + if (CollectionExpressionIDE0305Suppressor.IsInvocationAssignedToUnsupportedInterfaceType(context, syntaxNode)) + { + context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0304, diagnostic)); + } + } + } +} + +#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs index 6d5c75996..ddf17dedc 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs @@ -4,6 +4,7 @@ #if ROSLYN_4_12_0_OR_GREATER using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.CSharp; @@ -57,6 +58,14 @@ public static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAna // Try to get the syntax node matching the location of the diagnostic SyntaxNode? syntaxNode = diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); + return IsInvocationAssignedToUnsupportedInterfaceType(context, syntaxNode); + } + + /// + /// Checks whether a given invocation is assigning to an unsupported interface type. + /// + public static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAnalysisContext context, [NotNullWhen(true)] SyntaxNode? syntaxNode) + { // We expect to have found an invocation expression (eg. 'ToList()') if (syntaxNode?.Kind() is not SyntaxKind.InvocationExpression) { diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems index 834e19625..580c8bb91 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems @@ -17,6 +17,7 @@ + CsWinRTDiagnosticStrings.resx From b71c638128fc6f8cea312ca79e908ed0f44e5a52 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 25 Nov 2024 21:40:07 -0800 Subject: [PATCH 32/40] Fix analyzer tests --- .../DiagnosticAnalyzerTests.cs | 10 +++--- .../Helpers/CSharpAnalyzerTest{TAnalyzer}.cs | 31 ++++++++++++++----- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs b/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs index c7993b6c8..5dce32f29 100644 --- a/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs +++ b/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs @@ -26,7 +26,7 @@ void M() } """; - await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, editorconfig: [("CsWinRTAotOptimizerEnabled", "auto")]); } [TestMethod] @@ -48,7 +48,7 @@ void M() } """; - await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, editorconfig: [("CsWinRTAotOptimizerEnabled", "auto")]); } [TestMethod] @@ -71,7 +71,7 @@ void M(int x, IEnumerable y) } """; - await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, editorconfig: [("CsWinRTAotOptimizerEnabled", "auto")]); } [TestMethod] @@ -121,7 +121,7 @@ public static IMyInterface Create(ReadOnlySpan span) } """; - await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, editorconfig: [("CsWinRTAotOptimizerEnabled", "auto")]); } [TestMethod] @@ -147,6 +147,6 @@ void M(int x, IEnumerable y) } """; - await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, editorconfig: [("CsWinRTAotOptimizerEnabled", "auto")]); } } \ No newline at end of file diff --git a/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs b/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs index 294c68c33..a02f97635 100644 --- a/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs +++ b/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs @@ -1,10 +1,14 @@ +using System; +using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; using WinRT; namespace SourceGeneratorTest.Helpers; @@ -52,18 +56,29 @@ protected override ParseOptions CreateParseOptions() /// /// The source code to analyze. - /// Whether to enable unsafe blocks. /// The language version to use to run the test. - public static Task VerifyAnalyzerAsync( - string source, - bool allowUnsafeBlocks = true, - LanguageVersion languageVersion = LanguageVersion.CSharp12) + public static Task VerifyAnalyzerAsync(string source, params (string PropertyName, object PropertyValue)[] editorconfig) { - CSharpAnalyzerTest test = new(allowUnsafeBlocks, languageVersion) { TestCode = source }; + CSharpAnalyzerTest test = new(true, LanguageVersion.Latest) { TestCode = source }; test.TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net80; test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(ComWrappersSupport).Assembly.Location)); + // Add any editorconfig properties, if present + if (editorconfig.Length > 0) + { + test.SolutionTransforms.Add((solution, projectId) => + solution.AddAnalyzerConfigDocument( + DocumentId.CreateNewId(projectId), + "CsWinRTSourceGeneratorTest.editorconfig", + SourceText.From($""" + is_global = true + {string.Join(Environment.NewLine, editorconfig.Select(static p => $"build_property.{p.PropertyName} = {p.PropertyValue}"))} + """, + Encoding.UTF8), + filePath: "/CsWinRTSourceGeneratorTest.editorconfig")); + } + return test.RunAsync(CancellationToken.None); } } \ No newline at end of file From 41f78417e0df8b6ee7c232f044410bcb5a88da8a Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Tue, 26 Nov 2024 00:10:18 -0800 Subject: [PATCH 33/40] Don't pack .resx files for the generators --- nuget/Microsoft.Windows.CsWinRT.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.nuspec b/nuget/Microsoft.Windows.CsWinRT.nuspec index 676cb6a40..e5ce412e2 100644 --- a/nuget/Microsoft.Windows.CsWinRT.nuspec +++ b/nuget/Microsoft.Windows.CsWinRT.nuspec @@ -49,8 +49,8 @@ + - From 138be442fafd32aa8f0c66754ab6fa5cd8f0a69e Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Tue, 26 Nov 2024 10:39:41 -0800 Subject: [PATCH 34/40] Handle multiple '[CollectionBuilder]' attributes --- .../CollectionExpressionAnalyzer.cs | 13 ++++++------ src/Authoring/WinRT.SourceGenerator/Helper.cs | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs index f91426789..939fbd6de 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionAnalyzer.cs @@ -36,11 +36,12 @@ public override void Initialize(AnalysisContext context) return; } - // Get the symbol for '[CollectionBuilder]', we need it for lookups - if (context.Compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.CollectionBuilderAttribute") is not { } collectionBuilderSymbol) - { - return; - } + // Get the symbols for '[CollectionBuilder]', we need them for lookups. Note that we cannot just + // use 'GetTypeByMetadataName' here, as it's possible for the attribute to exist across multiple + // assemblies. This is the case if any referenced assemblies is using polyfills due to targeting + // an older TFM that does not have the attribute. We still want to work correctly in those cases. + // We can just use an array here, since in the vast majority of cases we only expect 1-2 items. + ImmutableArray collectionBuilderSymbols = context.Compilation.GetTypesByMetadataName("System.Runtime.CompilerServices.CollectionBuilderAttribute"); context.RegisterOperationAction(context => { @@ -67,7 +68,7 @@ SpecialType.System_Collections_Generic_ICollection_T or } // If the target interface type doesn't have '[CollectionBuilder]' on it, we should warn - if (!GeneratorHelper.HasAttributeWithType(typeSymbol, collectionBuilderSymbol)) + if (!GeneratorHelper.HasAttributeWithAnyType(typeSymbol, collectionBuilderSymbols)) { context.ReportDiagnostic(Diagnostic.Create( WinRTRules.NonEmptyCollectionExpressionTargetingNonBuilderInterfaceType, diff --git a/src/Authoring/WinRT.SourceGenerator/Helper.cs b/src/Authoring/WinRT.SourceGenerator/Helper.cs index 06b77a72f..9864b2b4a 100644 --- a/src/Authoring/WinRT.SourceGenerator/Helper.cs +++ b/src/Authoring/WinRT.SourceGenerator/Helper.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; @@ -650,6 +651,25 @@ public static bool HasAttributeWithType(ISymbol symbol, ITypeSymbol attributeTyp return false; } + /// + /// Checks whether or not a given symbol has an attribute with any types in a given sequence. + /// + /// The input instance to check. + /// The instances for the attributes type to look for. + /// Whether or not has an attribute with any of the specified types. + public static bool HasAttributeWithAnyType(ISymbol symbol, ImmutableArray attributeTypeSymbols) + { + foreach (AttributeData attribute in symbol.GetAttributes()) + { + if (attributeTypeSymbols.Contains(attribute.AttributeClass, SymbolEqualityComparer.Default)) + { + return true; + } + } + + return false; + } + /// /// Checks whether a symbol is annotated with [WinRTExposedType(typeof(WinRTManagedOnlyTypeDetails))]. /// From 66bac48952d1999af95881e1afcd15e7f7fb1e41 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Tue, 26 Nov 2024 11:33:24 -0800 Subject: [PATCH 35/40] Enable CsWinRT options in tests --- .../DiagnosticAnalyzerTests.cs | 37 +++++++++++++++++++ .../DiagnosticSuppressorTests.cs | 23 ++++++++++++ .../Helpers/CSharpAnalyzerTest{TAnalyzer}.cs | 2 +- .../CSharpSuppressorTest{TSuppressor}.cs | 35 ++++++++++++++++-- 4 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs b/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs index 5dce32f29..24eccf642 100644 --- a/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs +++ b/src/Tests/SourceGeneratorTest/DiagnosticAnalyzerTests.cs @@ -149,4 +149,41 @@ void M(int x, IEnumerable y) await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, editorconfig: [("CsWinRTAotOptimizerEnabled", "auto")]); } + + [TestMethod] + public async Task CollectionExpression_TargetingInterface_ReadOnly_NotEmpty_WithMultipleBuilderTypes_Warns() + { + const string source = """ + using System.Collections.Generic; + + namespace MyApp + { + class Test + { + void M(int x, IEnumerable y) + { + IEnumerable a = {|CsWinRT1032:[1, 2, 3]|}; + } + } + } + + namespace System.Runtime.CompilerServices + { + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] + internal sealed class CollectionBuilderAttribute : Attribute + { + public CollectionBuilderAttribute(Type builderType, string methodName) + { + BuilderType = builderType; + MethodName = methodName; + } + + public Type BuilderType { get; } + public string MethodName { get; } + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, editorconfig: [("CsWinRTAotOptimizerEnabled", "auto")]); + } } \ No newline at end of file diff --git a/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs b/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs index 050bd94e2..eb3a7587c 100644 --- a/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs +++ b/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs @@ -30,6 +30,29 @@ void TestMethod() """) .WithAnalyzer("Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer, Microsoft.CodeAnalysis.CSharp.CodeStyle") .WithSpecificDiagnostics(IDE0300) + .WithEditorconfig(("CsWinRTAotOptimizerEnabled", "auto")) + .RunAsync(); + } + + [TestMethod] + [Ignore("Bug in the Roslyn test runner that throws a 'TypeInitializationException'")] + public async Task CollectionExpression_IDE0300_ArrayCreation_TargetingInterfaceType_Suppressed() + { + await new CSharpSuppressorTest( + """ + using System.Collections.Generic; + + class TestClass + { + void TestMethod() + { + IEnumerable a = {|IDE0300:new[] {|} 1, 2, 3 }; + } + } + """) + .WithAnalyzer("Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer, Microsoft.CodeAnalysis.CSharp.CodeStyle") + .WithSpecificDiagnostics(IDE0300) + .WithEditorconfig(("CsWinRTAotOptimizerEnabled", "auto")) .RunAsync(); } } \ No newline at end of file diff --git a/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs b/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs index a02f97635..d6e86ace0 100644 --- a/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs +++ b/src/Tests/SourceGeneratorTest/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs @@ -56,7 +56,7 @@ protected override ParseOptions CreateParseOptions() /// /// The source code to analyze. - /// The language version to use to run the test. + /// The .editorconfig properties to use. public static Task VerifyAnalyzerAsync(string source, params (string PropertyName, object PropertyValue)[] editorconfig) { CSharpAnalyzerTest test = new(true, LanguageVersion.Latest) { TestCode = source }; diff --git a/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs b/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs index 844faea85..e2c1c5cde 100644 --- a/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs +++ b/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs @@ -1,15 +1,17 @@ -using System.Collections.Generic; -using System; -using System.Collections.Immutable; +using System; using System.ComponentModel; +using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Text; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using WinRT; -using Microsoft.CodeAnalysis.CSharp; namespace SourceGeneratorTest.Helpers; @@ -126,6 +128,31 @@ public CSharpSuppressorTest WithExpectedDiagnosticsResults(params D return this; } + + /// + /// Specifies the .editorconfig properties to use. + /// + /// The .editorconfig properties to use. + /// The current test instance. + public CSharpSuppressorTest WithEditorconfig(params (string PropertyName, object PropertyValue)[] editorconfig) + { + // Add any editorconfig properties, if present + if (editorconfig.Length > 0) + { + SolutionTransforms.Add((solution, projectId) => + solution.AddAnalyzerConfigDocument( + DocumentId.CreateNewId(projectId), + "CsWinRTSourceGeneratorTest.editorconfig", + SourceText.From($""" + is_global = true + {string.Join(Environment.NewLine, editorconfig.Select(static p => $"build_property.{p.PropertyName} = {p.PropertyValue}"))} + """, + Encoding.UTF8), + filePath: "/CsWinRTSourceGeneratorTest.editorconfig")); + } + + return this; + } } /// From 81d8d22ee817872a7a890717ba8ae91f780704e2 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Tue, 26 Nov 2024 11:34:38 -0800 Subject: [PATCH 36/40] Bump package and assembly versions --- build/AzurePipelineTemplates/CsWinRT-Variables.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/AzurePipelineTemplates/CsWinRT-Variables.yml b/build/AzurePipelineTemplates/CsWinRT-Variables.yml index a660d2e07..f1f62776e 100644 --- a/build/AzurePipelineTemplates/CsWinRT-Variables.yml +++ b/build/AzurePipelineTemplates/CsWinRT-Variables.yml @@ -3,11 +3,11 @@ variables: - name: MajorVersion value: 2 - name: MinorVersion - value: 2 + value: 3 - name: PatchVersion value: 0 - name: WinRT.Runtime.AssemblyVersion - value: '2.2.0.0' + value: '2.3.0.0' - name: Net5.SDK.Feed value: 'https://dotnetcli.blob.core.windows.net/dotnet' - name: Net8.SDK.Version From b8f5c5c792b88673bb302c64dee39be5c9a8170f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 4 Dec 2024 00:58:16 -0800 Subject: [PATCH 37/40] Fix IDE0303, IDE0305 suppressions --- .../CollectionExpressionIDE0303Suppressor.cs | 8 +++++++- .../CollectionExpressionIDE0304Suppressor.cs | 6 +----- .../CollectionExpressionIDE0305Suppressor.cs | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs index 74644cddc..97224dba8 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs @@ -41,7 +41,13 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) foreach (Diagnostic diagnostic in context.ReportedDiagnostics) { - if (CollectionExpressionIDE0305Suppressor.IsInvocationAssignedToUnsupportedInterfaceType(context, diagnostic)) + // The 'IDE0303' analyzer will add the location of the invocation expression in the additional locations set + if (diagnostic.AdditionalLocations is not [{ } invocationLocation, ..]) + { + continue; + } + + if (CollectionExpressionIDE0305Suppressor.IsInvocationAssignedToUnsupportedInterfaceType(context, invocationLocation)) { context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0303, diagnostic)); } diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs index 7ecf26d5a..ece981361 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs @@ -49,11 +49,7 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) continue; } - // Check the target invocation. The only thing we care about for this warning is whether the final invocation - // was being assigned to a concrete type (which is supported), or to a readonly interface type (which isn't). - SyntaxNode? syntaxNode = invocationLocation.SourceTree?.GetRoot(context.CancellationToken).FindNode(invocationLocation.SourceSpan); - - if (CollectionExpressionIDE0305Suppressor.IsInvocationAssignedToUnsupportedInterfaceType(context, syntaxNode)) + if (CollectionExpressionIDE0305Suppressor.IsInvocationAssignedToUnsupportedInterfaceType(context, invocationLocation)) { context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0304, diagnostic)); } diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs index ddf17dedc..9b974f724 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs @@ -43,7 +43,13 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) foreach (Diagnostic diagnostic in context.ReportedDiagnostics) { - if (IsInvocationAssignedToUnsupportedInterfaceType(context, diagnostic)) + // The 'IDE0305' analyzer will add the location of the invocation expression in the additional locations set + if (diagnostic.AdditionalLocations is not [{ } invocationLocation, ..]) + { + continue; + } + + if (IsInvocationAssignedToUnsupportedInterfaceType(context, invocationLocation)) { context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0305, diagnostic)); } @@ -53,18 +59,20 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) /// /// Checks whether a given diagnostic is over an invocation assigning to an unsupported interface type. /// - public static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAnalysisContext context, Diagnostic diagnostic) + public static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAnalysisContext context, Location location) { // Try to get the syntax node matching the location of the diagnostic - SyntaxNode? syntaxNode = diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); + SyntaxNode? syntaxNode = location.SourceTree?.GetRoot(context.CancellationToken).FindNode(location.SourceSpan); + // Check the target invocation. The only thing we care about for this warning is whether the final invocation + // was being assigned to a concrete type (which is supported), or to a readonly interface type (which isn't). return IsInvocationAssignedToUnsupportedInterfaceType(context, syntaxNode); } /// /// Checks whether a given invocation is assigning to an unsupported interface type. /// - public static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAnalysisContext context, [NotNullWhen(true)] SyntaxNode? syntaxNode) + private static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAnalysisContext context, [NotNullWhen(true)] SyntaxNode? syntaxNode) { // We expect to have found an invocation expression (eg. 'ToList()') if (syntaxNode?.Kind() is not SyntaxKind.InvocationExpression) From a3efe56714c9b83d09cce8b9db7ebae13866f2a0 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 4 Dec 2024 01:01:46 -0800 Subject: [PATCH 38/40] Fix IDE0300 suppressions --- .../CollectionExpressionIDE0300Suppressor.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs index 9ad8dbd93..141fdc8ae 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs @@ -47,6 +47,12 @@ public override void ReportSuppressions(SuppressionAnalysisContext context) // Try to get the syntax node matching the location of the diagnostic SyntaxNode? syntaxNode = diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); + // If the target node is an argument, unwrap it + if (syntaxNode?.Kind() is SyntaxKind.Argument) + { + syntaxNode = ((ArgumentSyntax)syntaxNode).Expression; + } + // We only support 3 types of expressions here: // Array initializer expressions: '{ 1, 2, 3 }' // Implicit array creation expressions: 'new[] { 1, 2, 3 }' From 3af932cdc090ea5ff604a457fd6c40d0965385e4 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 4 Dec 2024 10:07:13 -0800 Subject: [PATCH 39/40] Fix another 'ArgumentSyntax' case --- .../CollectionExpressionIDE0305Suppressor.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs index 9b974f724..14547dea9 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using WinRT.SourceGenerator; #nullable enable @@ -74,6 +75,12 @@ public static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAna /// private static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAnalysisContext context, [NotNullWhen(true)] SyntaxNode? syntaxNode) { + // If the target node is an argument, unwrap it + if (syntaxNode?.Kind() is SyntaxKind.Argument) + { + syntaxNode = ((ArgumentSyntax)syntaxNode).Expression; + } + // We expect to have found an invocation expression (eg. 'ToList()') if (syntaxNode?.Kind() is not SyntaxKind.InvocationExpression) { From 78ef22dd13d0117f3e567a39c3f7a1e04c7a4421 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 4 Dec 2024 17:17:30 -0800 Subject: [PATCH 40/40] Remove diagnostic suppressors --- .../CollectionExpressionIDE0300Suppressor.cs | 96 ---------- .../CollectionExpressionIDE0303Suppressor.cs | 58 ------ .../CollectionExpressionIDE0304Suppressor.cs | 60 ------ .../CollectionExpressionIDE0305Suppressor.cs | 107 ----------- .../CsWinRTDiagnosticStrings.resx | 2 +- .../WinRT.SourceGenerator.projitems | 5 - .../WinRTSuppressions.cs | 43 ----- .../DiagnosticSuppressorTests.cs | 58 ------ .../CSharpSuppressorTest{TSuppressor}.cs | 177 ------------------ 9 files changed, 1 insertion(+), 605 deletions(-) delete mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs delete mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs delete mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs delete mode 100644 src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs delete mode 100644 src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs delete mode 100644 src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs delete mode 100644 src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs deleted file mode 100644 index 141fdc8ae..000000000 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0300Suppressor.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#if ROSLYN_4_12_0_OR_GREATER - -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using WinRT.SourceGenerator; - -#nullable enable - -namespace Generator; - -/// -/// -/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. -/// -/// -/// This analyzer suppress diagnostics for cases like these: -/// -/// int[] a = { 1, 2, 3 }; -/// int[] b = new[] { 1, 2, 3 }; -/// int[] c = new int[] { 1, 2, 3 }; -/// -/// -/// -[DiagnosticAnalyzer(LanguageNames.CSharp)] -public sealed class CollectionExpressionIDE0300Suppressor : DiagnosticSuppressor -{ - /// - public override ImmutableArray SupportedSuppressions { get; } = [WinRTSuppressions.CollectionExpressionIDE0300]; - - /// - public override void ReportSuppressions(SuppressionAnalysisContext context) - { - // Skip the logic if CsWinRT is not in 'auto' mode - if (!GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation)) - { - return; - } - - foreach (Diagnostic diagnostic in context.ReportedDiagnostics) - { - // Try to get the syntax node matching the location of the diagnostic - SyntaxNode? syntaxNode = diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); - - // If the target node is an argument, unwrap it - if (syntaxNode?.Kind() is SyntaxKind.Argument) - { - syntaxNode = ((ArgumentSyntax)syntaxNode).Expression; - } - - // We only support 3 types of expressions here: - // Array initializer expressions: '{ 1, 2, 3 }' - // Implicit array creation expressions: 'new[] { 1, 2, 3 }' - // Array creation expressions: 'new int[] { 1, 2, 3 }' - if (syntaxNode?.Kind() is not (SyntaxKind.ArrayInitializerExpression or SyntaxKind.ImplicitArrayCreationExpression or SyntaxKind.ArrayCreationExpression)) - { - continue; - } - - // If the collection expression has no elements, we want to keep the diagnostic. That is - // because fixing the diagnostic (ie. switching to a collection expression) would be safe. - if (syntaxNode is - InitializerExpressionSyntax { Expressions: [] } or - ImplicitArrayCreationExpressionSyntax { Initializer.Expressions: [] } or - ArrayCreationExpressionSyntax { Initializer.Expressions: [] }) - { - continue; - } - - Microsoft.CodeAnalysis.TypeInfo typeInfo = context.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode, context.CancellationToken); - - // We might only opportunistically suppress the diagnostic when assigning to a generic interface type - if (typeInfo.ConvertedType is not INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true, IsUnboundGenericType: false } typeSymbol) - { - continue; - } - - // If the target type is either 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList', suppress the diagnostic. - // This is because using a collection expression in this case would produce an opaque type we cannot analyze for marshalling. - if (typeSymbol.ConstructedFrom.SpecialType is - SpecialType.System_Collections_Generic_IEnumerable_T or - SpecialType.System_Collections_Generic_IReadOnlyCollection_T or - SpecialType.System_Collections_Generic_IReadOnlyList_T) - { - context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0300, diagnostic)); - } - } - } -} - -#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs deleted file mode 100644 index 97224dba8..000000000 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0303Suppressor.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#if ROSLYN_4_12_0_OR_GREATER - -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using WinRT.SourceGenerator; - -#nullable enable - -namespace Generator; - -/// -/// -/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. -/// -/// -/// This analyzer suppress diagnostics for cases like these: -/// -/// ImmutableArray i = ImmutableArray.Create(1, 2, 3); -/// IEnumerable j = ImmutableArray.Create(1, 2, 3); -/// -/// -/// -[DiagnosticAnalyzer(LanguageNames.CSharp)] -public sealed class CollectionExpressionIDE0303Suppressor : DiagnosticSuppressor -{ - /// - public override ImmutableArray SupportedSuppressions { get; } = [WinRTSuppressions.CollectionExpressionIDE0303]; - - /// - public override void ReportSuppressions(SuppressionAnalysisContext context) - { - // Skip the logic if CsWinRT is not in 'auto' mode - if (!GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation)) - { - return; - } - - foreach (Diagnostic diagnostic in context.ReportedDiagnostics) - { - // The 'IDE0303' analyzer will add the location of the invocation expression in the additional locations set - if (diagnostic.AdditionalLocations is not [{ } invocationLocation, ..]) - { - continue; - } - - if (CollectionExpressionIDE0305Suppressor.IsInvocationAssignedToUnsupportedInterfaceType(context, invocationLocation)) - { - context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0303, diagnostic)); - } - } - } -} - -#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs deleted file mode 100644 index ece981361..000000000 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0304Suppressor.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#if ROSLYN_4_12_0_OR_GREATER - -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using WinRT.SourceGenerator; - -#nullable enable - -namespace Generator; - -/// -/// -/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. -/// -/// -/// This analyzer suppress diagnostics for cases like these: -/// -/// var builder = ImmutableArray.CreateBuilder(); -/// builder.Add(1); -/// builder.AddRange(new int[] { 5, 6, 7 }); -/// ImmutableArray i = builder.ToImmutable(); -/// -/// -/// -[DiagnosticAnalyzer(LanguageNames.CSharp)] -public sealed class CollectionExpressionIDE0304Suppressor : DiagnosticSuppressor -{ - /// - public override ImmutableArray SupportedSuppressions { get; } = [WinRTSuppressions.CollectionExpressionIDE0304]; - - /// - public override void ReportSuppressions(SuppressionAnalysisContext context) - { - // Skip the logic if CsWinRT is not in 'auto' mode - if (!GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation)) - { - return; - } - - foreach (Diagnostic diagnostic in context.ReportedDiagnostics) - { - // The 'IDE0304' analyzer will add the location of the invocation expression in the additional locations set - if (diagnostic.AdditionalLocations is not [{ } invocationLocation, ..]) - { - continue; - } - - if (CollectionExpressionIDE0305Suppressor.IsInvocationAssignedToUnsupportedInterfaceType(context, invocationLocation)) - { - context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0304, diagnostic)); - } - } - } -} - -#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs deleted file mode 100644 index 14547dea9..000000000 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#if ROSLYN_4_12_0_OR_GREATER - -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using WinRT.SourceGenerator; - -#nullable enable - -namespace Generator; - -/// -/// -/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios. -/// -/// -/// This analyzer suppress diagnostics for cases like these: -/// -/// List i = new[] { 1, 2, 3 }.ToList(); -/// IEnumerable j = new[] { 1, 2, 3 }.ToList(); -/// -/// -/// -[DiagnosticAnalyzer(LanguageNames.CSharp)] -public sealed class CollectionExpressionIDE0305Suppressor : DiagnosticSuppressor -{ - /// - public override ImmutableArray SupportedSuppressions { get; } = [WinRTSuppressions.CollectionExpressionIDE0305]; - - /// - public override void ReportSuppressions(SuppressionAnalysisContext context) - { - // Skip the logic if CsWinRT is not in 'auto' mode - if (!GeneratorExecutionContextHelper.IsCsWinRTAotOptimizerInAutoMode(context.Options.AnalyzerConfigOptionsProvider, context.Compilation)) - { - return; - } - - foreach (Diagnostic diagnostic in context.ReportedDiagnostics) - { - // The 'IDE0305' analyzer will add the location of the invocation expression in the additional locations set - if (diagnostic.AdditionalLocations is not [{ } invocationLocation, ..]) - { - continue; - } - - if (IsInvocationAssignedToUnsupportedInterfaceType(context, invocationLocation)) - { - context.ReportSuppression(Suppression.Create(WinRTSuppressions.CollectionExpressionIDE0305, diagnostic)); - } - } - } - - /// - /// Checks whether a given diagnostic is over an invocation assigning to an unsupported interface type. - /// - public static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAnalysisContext context, Location location) - { - // Try to get the syntax node matching the location of the diagnostic - SyntaxNode? syntaxNode = location.SourceTree?.GetRoot(context.CancellationToken).FindNode(location.SourceSpan); - - // Check the target invocation. The only thing we care about for this warning is whether the final invocation - // was being assigned to a concrete type (which is supported), or to a readonly interface type (which isn't). - return IsInvocationAssignedToUnsupportedInterfaceType(context, syntaxNode); - } - - /// - /// Checks whether a given invocation is assigning to an unsupported interface type. - /// - private static bool IsInvocationAssignedToUnsupportedInterfaceType(SuppressionAnalysisContext context, [NotNullWhen(true)] SyntaxNode? syntaxNode) - { - // If the target node is an argument, unwrap it - if (syntaxNode?.Kind() is SyntaxKind.Argument) - { - syntaxNode = ((ArgumentSyntax)syntaxNode).Expression; - } - - // We expect to have found an invocation expression (eg. 'ToList()') - if (syntaxNode?.Kind() is not SyntaxKind.InvocationExpression) - { - return false; - } - - Microsoft.CodeAnalysis.TypeInfo typeInfo = context.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode, context.CancellationToken); - - // We only want to suppress this diagnostic when the result of the invocation is assigned to an unsupported interface type - if (typeInfo.ConvertedType is not INamedTypeSymbol { TypeKind: TypeKind.Interface, IsGenericType: true, IsUnboundGenericType: false } typeSymbol) - { - return false; - } - - // Like for 'IDE0300', suppress diagnostics for 'IEnumerable', 'IReadOnlyCollection', or 'IReadOnlyList' - return - typeSymbol.ConstructedFrom.SpecialType is - SpecialType.System_Collections_Generic_IEnumerable_T or - SpecialType.System_Collections_Generic_IReadOnlyCollection_T or - SpecialType.System_Collections_Generic_IReadOnlyList_T; - } -} - -#endif diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx index 3cba34f43..39a4e5efb 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx @@ -296,6 +296,6 @@ Collection expression not safe for WinRT - Collection expressions targeting non mutable interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, a mutable interface type, or avoid using a collection expression in this case) + Collection expressions targeting non mutable interface type '{0}' do not have a defined concrete type, and are not supported for trimming and AOT compatibility with WinRT scenarios (consider changing the target type to be a concrete type, a mutable interface type, or add an explicit cast for either of these on the collection expression, eg. '(string[])["A", "B", "C"]') \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems index 580c8bb91..8b354ba4d 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.projitems @@ -15,10 +15,6 @@ - - - - CsWinRTDiagnosticStrings.resx True @@ -37,7 +33,6 @@ - diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs b/src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs deleted file mode 100644 index 5cbbd9b8f..000000000 --- a/src/Authoring/WinRT.SourceGenerator/WinRTSuppressions.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Microsoft.CodeAnalysis; - -namespace WinRT.SourceGenerator; - -/// -/// A container for all instances for errors reported by analyzers in this project. -/// -public static class WinRTSuppressions -{ - /// - /// Gets a for 'IDE0300', ie. "Use collection expression for array". - /// - public static readonly SuppressionDescriptor CollectionExpressionIDE0300 = new( - id: "CsWinRT2001", - suppressedDiagnosticId: "IDE0300", - justification: - "Using collection expressions when targeting 'IEnumerable', 'ICollection', 'IList', 'IReadOnlyCollection', " + - "or 'IReadOnlyList', when the collection expression is not empty, is not AOT compatible in WinRT scenarios"); - - /// - /// Gets a for 'IDE0303', ie. "Use collection expression for Create()". - /// - public static readonly SuppressionDescriptor CollectionExpressionIDE0303 = new( - id: "CsWinRT2002", - suppressedDiagnosticId: "IDE0303", - justification: "Using collection expressions when targeting an interface type without '[CollectionBuilder]' is not AOT compatible in WinRT scenarios"); - - /// - /// Gets a for 'IDE0304', ie. "Use collection expression for builder". - /// - public static readonly SuppressionDescriptor CollectionExpressionIDE0304 = new( - id: "CsWinRT2003", - suppressedDiagnosticId: "IDE0304", - justification: "Using collection expressions when targeting an interface type without '[CollectionBuilder]' is not AOT compatible in WinRT scenarios"); - - /// - /// Gets a for 'IDE0305', ie. "Use collection expression for fluent". - /// - public static readonly SuppressionDescriptor CollectionExpressionIDE0305 = new( - id: "CsWinRT2004", - suppressedDiagnosticId: "IDE0305", - justification: "Using collection expressions when targeting an interface type without '[CollectionBuilder]' is not AOT compatible in WinRT scenarios"); -} diff --git a/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs b/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs deleted file mode 100644 index eb3a7587c..000000000 --- a/src/Tests/SourceGeneratorTest/DiagnosticSuppressorTests.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Threading.Tasks; -using Generator; -using Microsoft.CodeAnalysis.Testing; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using SourceGeneratorTest.Helpers; - -namespace SourceGeneratorTest; - -[TestClass] -public sealed class DiagnosticSuppressorTests -{ - public static readonly DiagnosticResult IDE0300 = DiagnosticResult.CompilerWarning("IDE0300"); - - [TestMethod] - public async Task CollectionExpression_IDE0300_ArrayInitializer_TargetingArray_NotSuppressed() - { - await new CSharpSuppressorTest( - """ - class TestClass - { - private int[] f = {|IDE0300:{|} 1, 2, 3 }; - - void TestMethod() - { - int[] a = {|IDE0300:{|} 1, 2, 3 }; - } - - public int[] P { get; } = {|IDE0300:{|} 1, 2, 3 }; - } - """) - .WithAnalyzer("Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer, Microsoft.CodeAnalysis.CSharp.CodeStyle") - .WithSpecificDiagnostics(IDE0300) - .WithEditorconfig(("CsWinRTAotOptimizerEnabled", "auto")) - .RunAsync(); - } - - [TestMethod] - [Ignore("Bug in the Roslyn test runner that throws a 'TypeInitializationException'")] - public async Task CollectionExpression_IDE0300_ArrayCreation_TargetingInterfaceType_Suppressed() - { - await new CSharpSuppressorTest( - """ - using System.Collections.Generic; - - class TestClass - { - void TestMethod() - { - IEnumerable a = {|IDE0300:new[] {|} 1, 2, 3 }; - } - } - """) - .WithAnalyzer("Microsoft.CodeAnalysis.CSharp.UseCollectionExpression.CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer, Microsoft.CodeAnalysis.CSharp.CodeStyle") - .WithSpecificDiagnostics(IDE0300) - .WithEditorconfig(("CsWinRTAotOptimizerEnabled", "auto")) - .RunAsync(); - } -} \ No newline at end of file diff --git a/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs b/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs deleted file mode 100644 index e2c1c5cde..000000000 --- a/src/Tests/SourceGeneratorTest/Helpers/CSharpSuppressorTest{TSuppressor}.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; -using System.ComponentModel; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Testing; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Text; -using WinRT; - -namespace SourceGeneratorTest.Helpers; - -/// -/// A custom for testing diagnostic suppressors. -/// -/// The type of the suppressor to test. -// Adapted from https://github.com/ImmediatePlatform/Immediate.Validations -public sealed class CSharpSuppressorTest : CSharpAnalyzerTest - where TSuppressor : DiagnosticSuppressor, new() -{ - /// - /// The list of analyzers to run on the input code. - /// - private readonly List _analyzers = []; - - /// - /// Whether to enable unsafe blocks. - /// - private readonly bool _allowUnsafeBlocks; - - /// - /// The C# language version to use to parse code. - /// - private readonly LanguageVersion _languageVersion; - - /// - /// Creates a new instance with the specified parameters. - /// - /// The source code to analyze. - /// Whether to enable unsafe blocks. - /// The language version to use to run the test. - public CSharpSuppressorTest( - string source, - bool allowUnsafeBlocks = true, - LanguageVersion languageVersion = LanguageVersion.CSharp12) - { - _allowUnsafeBlocks = allowUnsafeBlocks; - _languageVersion = languageVersion; - - TestCode = source; - TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net80; - TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(ComWrappersSupport).Assembly.Location)); - } - - /// - protected override IEnumerable GetDiagnosticAnalyzers() - { - return base.GetDiagnosticAnalyzers().Concat(_analyzers); - } - - /// - protected override CompilationOptions CreateCompilationOptions() - { - return new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: _allowUnsafeBlocks); - } - - /// - protected override ParseOptions CreateParseOptions() - { - return new CSharpParseOptions(_languageVersion, DocumentationMode.Diagnose); - } - - /// - /// Adds a new analyzer to the set of analyzers to run on the input code. - /// - /// The type of analyzer to activate. - /// The current test instance. - public CSharpSuppressorTest WithAnalyzer( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] string assemblyQualifiedTypeName) - { - _analyzers.Add((DiagnosticAnalyzer)Activator.CreateInstance(Type.GetType(assemblyQualifiedTypeName))); - - return this; - } - - /// - /// Specifies the diagnostics to enable. - /// - /// The set of diagnostics. - /// The current test instance. - public CSharpSuppressorTest WithSpecificDiagnostics(params DiagnosticResult[] diagnostics) - { - ImmutableDictionary diagnosticOptions = diagnostics.ToImmutableDictionary( - descriptor => descriptor.Id, - descriptor => descriptor.Severity.ToReportDiagnostic()); - - // Transform to enable the diagnostics - Solution EnableDiagnostics(Solution solution, ProjectId projectId) - { - CompilationOptions options = - solution.GetProject(projectId)?.CompilationOptions - ?? throw new InvalidOperationException("Compilation options missing."); - - return solution.WithProjectCompilationOptions( - projectId, - options.WithSpecificDiagnosticOptions(diagnosticOptions)); - } - - SolutionTransforms.Clear(); - SolutionTransforms.Add(EnableDiagnostics); - - return this; - } - - /// - /// Specifies the diagnostics that should be produced. - /// - /// The set of diagnostics. - /// The current test instance. - public CSharpSuppressorTest WithExpectedDiagnosticsResults(params DiagnosticResult[] diagnostics) - { - ExpectedDiagnostics.AddRange(diagnostics); - - return this; - } - - /// - /// Specifies the .editorconfig properties to use. - /// - /// The .editorconfig properties to use. - /// The current test instance. - public CSharpSuppressorTest WithEditorconfig(params (string PropertyName, object PropertyValue)[] editorconfig) - { - // Add any editorconfig properties, if present - if (editorconfig.Length > 0) - { - SolutionTransforms.Add((solution, projectId) => - solution.AddAnalyzerConfigDocument( - DocumentId.CreateNewId(projectId), - "CsWinRTSourceGeneratorTest.editorconfig", - SourceText.From($""" - is_global = true - {string.Join(Environment.NewLine, editorconfig.Select(static p => $"build_property.{p.PropertyName} = {p.PropertyValue}"))} - """, - Encoding.UTF8), - filePath: "/CsWinRTSourceGeneratorTest.editorconfig")); - } - - return this; - } -} - -/// -/// Extensions for . -/// -file static class DiagnosticSeverityExtensions -{ - /// - /// Converts a value into a one. - /// - public static ReportDiagnostic ToReportDiagnostic(this DiagnosticSeverity severity) - { - return severity switch - { - DiagnosticSeverity.Hidden => ReportDiagnostic.Hidden, - DiagnosticSeverity.Info => ReportDiagnostic.Info, - DiagnosticSeverity.Warning => ReportDiagnostic.Warn, - DiagnosticSeverity.Error => ReportDiagnostic.Error, - _ => throw new InvalidEnumArgumentException(nameof(severity), (int)severity, typeof(DiagnosticSeverity)), - }; - } -} \ No newline at end of file