From 2b3f80f42a3a2118b0523555d8650e5d3b2a1bfd Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 25 Nov 2024 19:02:36 -0800 Subject: [PATCH] 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..3b0b5ea87 100644 --- a/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs +++ b/src/Authoring/WinRT.SourceGenerator/CollectionExpressions/CollectionExpressionIDE0305Suppressor.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.CSharp; using WinRT.SourceGenerator; +using System.Diagnostics.CodeAnalysis; #nullable enable @@ -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