| File: RequestDelegateGeneratorSuppressor.cs | Web Access |
| Project: src\aspnetcore\src\Http\Http.Extensions\gen\Microsoft.AspNetCore.Http.RequestDelegateGenerator\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj (Microsoft.AspNetCore.Http.RequestDelegateGenerator) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using System.Linq; using Microsoft.AspNetCore.App.Analyzers.Infrastructure; using Microsoft.AspNetCore.Http.RequestDelegateGenerator.StaticRouteHandlerModel; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; /* * This class contains the logic for suppressing diagnostics that are * emitted by the linker analyzers when encountering the framework-provided * `Map` invocations. Pending the completion of https://github.com/dotnet/roslyn/issues/68669, * this workaround is necessary to apply these suppressions for `Map` invocations that the RDG * is able to generate code at compile time for that the analyzer is not able to resolve. */ namespace Microsoft.AspNetCore.Http.RequestDelegateGenerator; [DiagnosticAnalyzer(LanguageNames.CSharp)] public sealed class RequestDelegateGeneratorSuppressor : DiagnosticSuppressor { private static readonly SuppressionDescriptor SuppressRUCDiagnostic = new( id: "RDGS001", suppressedDiagnosticId: "IL2026", justification: "The target method has been intercepted by a statically generated variant."); private static readonly SuppressionDescriptor SuppressRDCDiagnostic = new( id: "RDGS002", suppressedDiagnosticId: "IL3050", justification: "The target method has been intercepted by a statically generated variant."); public override void ReportSuppressions(SuppressionAnalysisContext context) { foreach (var diagnostic in context.ReportedDiagnostics) { if (diagnostic.Id != SuppressRDCDiagnostic.SuppressedDiagnosticId && diagnostic.Id != SuppressRUCDiagnostic.SuppressedDiagnosticId) { continue; } var location = diagnostic.AdditionalLocations.Count > 0 ? diagnostic.AdditionalLocations[0] : diagnostic.Location; if (location.SourceTree is not { } sourceTree) { continue; } // The trim analyzer changed from warning on the InvocationExpression to the MemberAccessExpression in https://github.com/dotnet/runtime/pull/110086. // To account for this, we need to check if the location is an InvocationExpression or a child of an InvocationExpression. var node = sourceTree.GetRoot().FindNode(location.SourceSpan) switch { InvocationExpressionSyntax s => s, { Parent: InvocationExpressionSyntax s } => s, _ => null, }; if (node is null || !node.TryGetMapMethodName(out var method) || !InvocationOperationExtensions.KnownMethods.Contains(method)) { continue; } var semanticModel = context.GetSemanticModel(sourceTree); var operation = semanticModel.GetOperation(node, context.CancellationToken); var wellKnownTypes = WellKnownTypes.GetOrCreate(semanticModel.Compilation); if (operation.IsValidOperation(wellKnownTypes, out var invocationOperation)) { var endpoint = new Endpoint(invocationOperation, wellKnownTypes, semanticModel); if (endpoint.Diagnostics.Count == 0) { var targetSuppression = diagnostic.Id == SuppressRUCDiagnostic.SuppressedDiagnosticId ? SuppressRUCDiagnostic : SuppressRDCDiagnostic; context.ReportSuppression(Suppression.Create(targetSuppression, diagnostic)); } } } } public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions => ImmutableArray.Create(SuppressRUCDiagnostic, SuppressRDCDiagnostic); }