Skip to content

Commit

Permalink
Add 'CollectionExpressionIDE0304Suppressor'
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio0694 committed Nov 26, 2024
1 parent acca54d commit 2b3f80f
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// <para>
/// A diagnostic suppressor to suppress collection expression warnings where needed for AOT compatibility in WinRT scenarios.
/// </para>
/// <para>
/// This analyzer suppress diagnostics for cases like these:
/// <code lang="csharp">
/// var builder = ImmutableArray.CreateBuilder<int>();
/// builder.Add(1);
/// builder.AddRange(new int[] { 5, 6, 7 });
/// ImmutableArray<int> i = builder.ToImmutable();
/// </code>
/// </para>
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class CollectionExpressionIDE0304Suppressor : DiagnosticSuppressor
{
/// <inheritdoc/>
public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions { get; } = [WinRTSuppressions.CollectionExpressionIDE0304];

/// <inheritdoc/>
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.CSharp;
using WinRT.SourceGenerator;
using System.Diagnostics.CodeAnalysis;

#nullable enable

Expand Down Expand Up @@ -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);
}

/// <summary>
/// Checks whether a given invocation is assigning to an unsupported interface type.
/// </summary>
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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<Compile Include="$(MSBuildThisFileDirectory)CollectionExpressions\CollectionExpressionAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionExpressions\CollectionExpressionIDE0300Suppressor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionExpressions\CollectionExpressionIDE0303Suppressor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionExpressions\CollectionExpressionIDE0304Suppressor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionExpressions\CollectionExpressionIDE0305Suppressor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CsWinRTDiagnosticStrings.Designer.cs">
<DependentUpon>CsWinRTDiagnosticStrings.resx</DependentUpon>
Expand Down

0 comments on commit 2b3f80f

Please sign in to comment.