| File: RouteHandlers\DisallowReturningActionResultFromMapMethods.cs | Web Access |
| Project: src\aspnetcore\src\Framework\AspNetCoreAnalyzers\src\Analyzers\Microsoft.AspNetCore.App.Analyzers.csproj (Microsoft.AspNetCore.App.Analyzers) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Linq; using Microsoft.AspNetCore.App.Analyzers.Infrastructure; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; namespace Microsoft.AspNetCore.Analyzers.RouteHandlers; using WellKnownType = WellKnownTypeData.WellKnownType; public partial class RouteHandlerAnalyzer : DiagnosticAnalyzer { private static void DisallowReturningActionResultFromMapMethods( in OperationAnalysisContext context, WellKnownTypes wellKnownTypes, IInvocationOperation invocationOperation, IAnonymousFunctionOperation anonymousFunction, SyntaxNode nodeForError) { DisallowReturningActionResultFromMapMethods(in context, wellKnownTypes, invocationOperation, anonymousFunction.Symbol, anonymousFunction.Body, nodeForError); } private static void DisallowReturningActionResultFromMapMethods( in OperationAnalysisContext context, WellKnownTypes wellKnownTypes, IInvocationOperation invocationOperation, IMethodSymbol methodSymbol, IBlockOperation? methodBody, SyntaxNode nodeForError) { var returnType = UnwrapPossibleAsyncReturnType(methodSymbol.ReturnType); if (wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_IResult).IsAssignableFrom(returnType)) { // This type returns some form of IResult. Nothing to do here. return; } if (methodBody is null && (wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Mvc_IActionResult).IsAssignableFrom(returnType) || wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Mvc_Infrastructure_IConvertToActionResult).IsAssignableFrom(returnType))) { // if we don't have a method body, and the action is IResult or ActionResult<T> returning, produce diagnostics for the entire method. context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.DoNotReturnActionResultsFromRouteHandlers, nodeForError.GetLocation(), invocationOperation.TargetMethod.Name)); return; } foreach (var returnOperation in methodBody.Descendants().OfType<IReturnOperation>()) { if (returnOperation.ReturnedValue is null or IInvalidOperation) { continue; } var returnedValue = returnOperation.ReturnedValue; if (returnedValue is IConversionOperation conversionOperation) { returnedValue = conversionOperation.Operand; } var type = returnedValue.Type; if (type is null) { continue; } if (wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_IResult).IsAssignableFrom(type)) { continue; } if (wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Mvc_IActionResult).IsAssignableFrom(type)) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.DoNotReturnActionResultsFromRouteHandlers, returnOperation.Syntax.GetLocation(), invocationOperation.TargetMethod.Name)); } } } private static ITypeSymbol UnwrapPossibleAsyncReturnType(ITypeSymbol returnType) { if (returnType is not INamedTypeSymbol { Name: "Task" or "ValueTask", IsGenericType: true, TypeArguments: { Length: 1 } } taskLike) { return returnType; } return taskLike.TypeArguments[0]; } }