Add analyzer support for status code methods and constructors
This commit is contained in:
parent
2a426dfea5
commit
ffdbea9dc1
|
|
@ -123,7 +123,7 @@ namespace Microsoft.CodeAnalysis
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool HasAttribute(this ISymbol symbol, ITypeSymbol attribute)
|
public static bool HasAttribute(this ISymbol symbol, ITypeSymbol attribute)
|
||||||
{
|
{
|
||||||
foreach (var declaredAttribute in symbol.GetAttributes())
|
foreach (var declaredAttribute in symbol.GetAttributes())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,11 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!method.ReturnsVoid)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (method.Parameters.Length != disposableDispose.Parameters.Length)
|
if (method.Parameters.Length != disposableDispose.Parameters.Length)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
|
|
@ -24,6 +25,11 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
ProducesDefaultResponseTypeAttribute = compilation.GetTypeByMetadataName(ApiSymbolNames.ProducesDefaultResponseTypeAttribute);
|
ProducesDefaultResponseTypeAttribute = compilation.GetTypeByMetadataName(ApiSymbolNames.ProducesDefaultResponseTypeAttribute);
|
||||||
ProducesResponseTypeAttribute = compilation.GetTypeByMetadataName(ApiSymbolNames.ProducesResponseTypeAttribute);
|
ProducesResponseTypeAttribute = compilation.GetTypeByMetadataName(ApiSymbolNames.ProducesResponseTypeAttribute);
|
||||||
|
|
||||||
|
StatusCodeValueAttribute = compilation.GetTypeByMetadataName(ApiSymbolNames.StatusCodeValueAttribute);
|
||||||
|
|
||||||
|
var statusCodeActionResult = compilation.GetTypeByMetadataName(ApiSymbolNames.IStatusCodeActionResult);
|
||||||
|
StatusCodeActionResultStatusProperty = (IPropertySymbol)statusCodeActionResult.GetMembers("StatusCode")[0];
|
||||||
|
|
||||||
var disposable = compilation.GetSpecialType(SpecialType.System_IDisposable);
|
var disposable = compilation.GetSpecialType(SpecialType.System_IDisposable);
|
||||||
var members = disposable.GetMembers(nameof(IDisposable.Dispose));
|
var members = disposable.GetMembers(nameof(IDisposable.Dispose));
|
||||||
IDisposableDispose = members.Length == 1 ? (IMethodSymbol)members[0] : null;
|
IDisposableDispose = members.Length == 1 ? (IMethodSymbol)members[0] : null;
|
||||||
|
|
@ -47,6 +53,8 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
|
|
||||||
public IMethodSymbol IDisposableDispose { get; }
|
public IMethodSymbol IDisposableDispose { get; }
|
||||||
|
|
||||||
|
public IPropertySymbol StatusCodeActionResultStatusProperty { get; }
|
||||||
|
|
||||||
public ITypeSymbol ModelStateDictionary { get; }
|
public ITypeSymbol ModelStateDictionary { get; }
|
||||||
|
|
||||||
public INamedTypeSymbol NonActionAttribute { get; }
|
public INamedTypeSymbol NonActionAttribute { get; }
|
||||||
|
|
@ -56,5 +64,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
public INamedTypeSymbol ProducesDefaultResponseTypeAttribute { get; }
|
public INamedTypeSymbol ProducesDefaultResponseTypeAttribute { get; }
|
||||||
|
|
||||||
public INamedTypeSymbol ProducesResponseTypeAttribute { get; }
|
public INamedTypeSymbol ProducesResponseTypeAttribute { get; }
|
||||||
|
|
||||||
|
public INamedTypeSymbol StatusCodeValueAttribute { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
|
|
||||||
public const string IActionResult = "Microsoft.AspNetCore.Mvc.IActionResult";
|
public const string IActionResult = "Microsoft.AspNetCore.Mvc.IActionResult";
|
||||||
|
|
||||||
|
public const string IStatusCodeActionResult = "Microsoft.AspNetCore.Mvc.Infrastructure.IStatusCodeActionResult";
|
||||||
|
|
||||||
public const string ModelStateDictionary = "Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary";
|
public const string ModelStateDictionary = "Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary";
|
||||||
|
|
||||||
public const string NonActionAttribute = "Microsoft.AspNetCore.Mvc.NonActionAttribute";
|
public const string NonActionAttribute = "Microsoft.AspNetCore.Mvc.NonActionAttribute";
|
||||||
|
|
@ -34,5 +36,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
public const string ProducesResponseTypeAttribute = "Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute";
|
public const string ProducesResponseTypeAttribute = "Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute";
|
||||||
|
|
||||||
public const string HttpStatusCodes = "Microsoft.AspNetCore.Http.StatusCodes";
|
public const string HttpStatusCodes = "Microsoft.AspNetCore.Http.StatusCodes";
|
||||||
|
|
||||||
|
public const string StatusCodeValueAttribute = "Microsoft.AspNetCore.Mvc.Infrastructure.StatusCodeValueAttribute";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,8 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
}
|
}
|
||||||
|
|
||||||
return Array.Empty<DeclaredApiResponseMetadata>();
|
return Array.Empty<DeclaredApiResponseMetadata>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IMethodSymbol GetMethodFromConventionMethodAttribute(ApiControllerSymbolCache symbolCache, IMethodSymbol method)
|
private static IMethodSymbol GetMethodFromConventionMethodAttribute(ApiControllerSymbolCache symbolCache, IMethodSymbol method)
|
||||||
{
|
{
|
||||||
var attribute = method.GetAttributes(symbolCache.ApiConventionMethodAttribute, inherit: true)
|
var attribute = method.GetAttributes(symbolCache.ApiConventionMethodAttribute, inherit: true)
|
||||||
|
|
@ -222,6 +223,12 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
|
|
||||||
foreach (var returnStatementSyntax in methodSyntax.DescendantNodes(_shouldDescendIntoChildren).OfType<ReturnStatementSyntax>())
|
foreach (var returnStatementSyntax in methodSyntax.DescendantNodes(_shouldDescendIntoChildren).OfType<ReturnStatementSyntax>())
|
||||||
{
|
{
|
||||||
|
if (returnStatementSyntax.IsMissing || returnStatementSyntax.Expression.IsMissing)
|
||||||
|
{
|
||||||
|
// Ignore malformed return statements.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var responseMetadata = InspectReturnStatementSyntax(
|
var responseMetadata = InspectReturnStatementSyntax(
|
||||||
symbolCache,
|
symbolCache,
|
||||||
semanticModel,
|
semanticModel,
|
||||||
|
|
@ -248,11 +255,6 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var returnExpression = returnStatementSyntax.Expression;
|
var returnExpression = returnStatementSyntax.Expression;
|
||||||
if (returnExpression.IsMissing)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var typeInfo = semanticModel.GetTypeInfo(returnExpression, cancellationToken);
|
var typeInfo = semanticModel.GetTypeInfo(returnExpression, cancellationToken);
|
||||||
if (typeInfo.Type.TypeKind == TypeKind.Error)
|
if (typeInfo.Type.TypeKind == TypeKind.Error)
|
||||||
{
|
{
|
||||||
|
|
@ -267,25 +269,176 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
|
|
||||||
if (defaultStatusCodeAttribute != null)
|
if (defaultStatusCodeAttribute != null)
|
||||||
{
|
{
|
||||||
var statusCode = GetDefaultStatusCode(defaultStatusCodeAttribute);
|
var defaultStatusCode = GetDefaultStatusCode(defaultStatusCodeAttribute);
|
||||||
if (statusCode == null)
|
if (defaultStatusCode == null)
|
||||||
{
|
{
|
||||||
// Unable to read the status code even though the attribute exists.
|
// Unable to read the status code even though the attribute exists.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ActualApiResponseMetadata(returnStatementSyntax, statusCode.Value);
|
return new ActualApiResponseMetadata(returnStatementSyntax, defaultStatusCode.Value);
|
||||||
}
|
}
|
||||||
else if (!symbolCache.IActionResult.IsAssignableFrom(statementReturnType))
|
|
||||||
|
if (!symbolCache.IActionResult.IsAssignableFrom(statementReturnType))
|
||||||
{
|
{
|
||||||
// Return expression does not have a DefaultStatusCodeAttribute and it is not
|
// Return expression does not have a DefaultStatusCodeAttribute and it is not
|
||||||
// an instance of IActionResult. Must be returning the "model".
|
// an instance of IActionResult. Must be returning the "model".
|
||||||
return new ActualApiResponseMetadata(returnStatementSyntax);
|
return new ActualApiResponseMetadata(returnStatementSyntax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int statusCode;
|
||||||
|
switch (returnExpression)
|
||||||
|
{
|
||||||
|
case InvocationExpressionSyntax invocation:
|
||||||
|
// Covers the 'return StatusCode(200)' case.
|
||||||
|
if (TryGetParameterStatusCode(symbolCache, semanticModel, invocation.Expression, invocation.ArgumentList, cancellationToken, out statusCode))
|
||||||
|
{
|
||||||
|
return new ActualApiResponseMetadata(returnStatementSyntax, statusCode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectCreationExpressionSyntax creation:
|
||||||
|
// Covers the 'return new ObjectResult(...) { StatusCode = 200 }' case.
|
||||||
|
if (TryGetInitializerStatusCode(symbolCache, semanticModel, creation.Initializer, cancellationToken, out statusCode))
|
||||||
|
{
|
||||||
|
return new ActualApiResponseMetadata(returnStatementSyntax, statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Covers the 'return new StatusCodeResult(200) case.
|
||||||
|
if (TryGetParameterStatusCode(symbolCache, semanticModel, creation, creation.ArgumentList, cancellationToken, out statusCode))
|
||||||
|
{
|
||||||
|
return new ActualApiResponseMetadata(returnStatementSyntax, statusCode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool TryGetInitializerStatusCode(
|
||||||
|
in ApiControllerSymbolCache symbolCache,
|
||||||
|
SemanticModel semanticModel,
|
||||||
|
InitializerExpressionSyntax initializer,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
out int statusCode)
|
||||||
|
{
|
||||||
|
if (initializer == null)
|
||||||
|
{
|
||||||
|
statusCode = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < initializer.Expressions.Count; i++)
|
||||||
|
{
|
||||||
|
if (!(initializer.Expressions[i] is AssignmentExpressionSyntax assignment))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assignment.Left is IdentifierNameSyntax identifier)
|
||||||
|
{
|
||||||
|
var symbolInfo = semanticModel.GetSymbolInfo(identifier, cancellationToken);
|
||||||
|
|
||||||
|
if (symbolInfo.Symbol is IPropertySymbol property && IsInterfaceImplementation(property, symbolCache.StatusCodeActionResultStatusProperty))
|
||||||
|
{
|
||||||
|
return TryGetExpressionStatusCode(semanticModel, assignment.Right, cancellationToken, out statusCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
statusCode = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsInterfaceImplementation(IPropertySymbol property, IPropertySymbol statusCodeActionResultStatusProperty)
|
||||||
|
{
|
||||||
|
if (property.Name != statusCodeActionResultStatusProperty.Name)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < property.ExplicitInterfaceImplementations.Length; i++)
|
||||||
|
{
|
||||||
|
if (property.ExplicitInterfaceImplementations[i] == statusCodeActionResultStatusProperty)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var implementedProperty = property.ContainingType.FindImplementationForInterfaceMember(statusCodeActionResultStatusProperty);
|
||||||
|
return implementedProperty == property;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetParameterStatusCode(
|
||||||
|
in ApiControllerSymbolCache symbolCache,
|
||||||
|
SemanticModel semanticModel,
|
||||||
|
ExpressionSyntax expression,
|
||||||
|
BaseArgumentListSyntax argumentList,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
out int statusCode)
|
||||||
|
{
|
||||||
|
var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken);
|
||||||
|
|
||||||
|
if (!(symbolInfo.Symbol is IMethodSymbol method))
|
||||||
|
{
|
||||||
|
statusCode = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < method.Parameters.Length; i++)
|
||||||
|
{
|
||||||
|
var parameter = method.Parameters[i];
|
||||||
|
if (!parameter.HasAttribute(symbolCache.StatusCodeValueAttribute))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var argument = argumentList.Arguments[parameter.Ordinal];
|
||||||
|
return TryGetExpressionStatusCode(semanticModel, argument.Expression, cancellationToken, out statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
statusCode = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetExpressionStatusCode(
|
||||||
|
SemanticModel semanticModel,
|
||||||
|
ExpressionSyntax expression,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
out int statusCode)
|
||||||
|
{
|
||||||
|
if (expression is LiteralExpressionSyntax literal && literal.Token.Value is int literalStatusCode)
|
||||||
|
{
|
||||||
|
// Covers the 'return StatusCode(200)' case.
|
||||||
|
statusCode = literalStatusCode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expression is IdentifierNameSyntax || expression is MemberAccessExpressionSyntax)
|
||||||
|
{
|
||||||
|
var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken);
|
||||||
|
|
||||||
|
if (symbolInfo.Symbol is IFieldSymbol field && field.HasConstantValue && field.ConstantValue is int constantStatusCode)
|
||||||
|
{
|
||||||
|
// Covers the 'return StatusCode(StatusCodes.Status200OK)' case.
|
||||||
|
// It also covers the 'return StatusCode(StatusCode)' case, where 'StatusCode' is a constant field.
|
||||||
|
statusCode = constantStatusCode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbolInfo.Symbol is ILocalSymbol local && local.HasConstantValue && local.ConstantValue is int localStatusCode)
|
||||||
|
{
|
||||||
|
// Covers the 'return StatusCode(statusCode)' case, where 'statusCode' is a local constant.
|
||||||
|
statusCode = localStatusCode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
statusCode = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool ShouldDescendIntoChildren(SyntaxNode syntaxNode)
|
private static bool ShouldDescendIntoChildren(SyntaxNode syntaxNode)
|
||||||
{
|
{
|
||||||
return !syntaxNode.IsKind(SyntaxKind.LocalFunctionStatement) &&
|
return !syntaxNode.IsKind(SyntaxKind.LocalFunctionStatement) &&
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Core;
|
using Microsoft.AspNetCore.Mvc.Core;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
|
@ -200,7 +201,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// <param name="statusCode">The status code to set on the response.</param>
|
/// <param name="statusCode">The status code to set on the response.</param>
|
||||||
/// <returns>The created <see cref="StatusCodeResult"/> object for the response.</returns>
|
/// <returns>The created <see cref="StatusCodeResult"/> object for the response.</returns>
|
||||||
[NonAction]
|
[NonAction]
|
||||||
public virtual StatusCodeResult StatusCode(int statusCode)
|
public virtual StatusCodeResult StatusCode([StatusCodeValue] int statusCode)
|
||||||
=> new StatusCodeResult(statusCode);
|
=> new StatusCodeResult(statusCode);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -210,10 +211,12 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// <param name="value">The value to set on the <see cref="ObjectResult"/>.</param>
|
/// <param name="value">The value to set on the <see cref="ObjectResult"/>.</param>
|
||||||
/// <returns>The created <see cref="ObjectResult"/> object for the response.</returns>
|
/// <returns>The created <see cref="ObjectResult"/> object for the response.</returns>
|
||||||
[NonAction]
|
[NonAction]
|
||||||
public virtual ObjectResult StatusCode(int statusCode, object value)
|
public virtual ObjectResult StatusCode([StatusCodeValue] int statusCode, object value)
|
||||||
{
|
{
|
||||||
var result = new ObjectResult(value);
|
var result = new ObjectResult(value)
|
||||||
result.StatusCode = statusCode;
|
{
|
||||||
|
StatusCode = statusCode
|
||||||
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
|
||||||
|
internal sealed class StatusCodeValueAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// with the given <paramref name="statusCode"/>.
|
/// with the given <paramref name="statusCode"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="statusCode">The HTTP status code of the response.</param>
|
/// <param name="statusCode">The HTTP status code of the response.</param>
|
||||||
public StatusCodeResult(int statusCode)
|
public StatusCodeResult([StatusCodeValue] int statusCode)
|
||||||
{
|
{
|
||||||
StatusCode = statusCode;
|
StatusCode = statusCode;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,18 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers
|
||||||
[Fact]
|
[Fact]
|
||||||
public Task CodeFixAddsFullyQualifiedProducesResponseType() => RunTest();
|
public Task CodeFixAddsFullyQualifiedProducesResponseType() => RunTest();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task CodeFixAddsNumericLiteralForNonExistingStatusCodeConstants() => RunTest();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task CodeFixAddsStatusCodesFromMethodParameters() => RunTest();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task CodeFixAddsStatusCodesFromConstructorParameters() => RunTest();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task CodeFixAddsStatusCodesFromObjectInitializer() => RunTest();
|
||||||
|
|
||||||
private async Task RunTest([CallerMemberName] string testMethod = "")
|
private async Task RunTest([CallerMemberName] string testMethod = "")
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers._INPUT_
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
public class CodeFixAddsNumericLiteralForNonExistingStatusCodeConstantsController : ControllerBase
|
||||||
|
{
|
||||||
|
public IActionResult GetItem(int id)
|
||||||
|
{
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
return StatusCode(345);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(new object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers._OUTPUT_
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
public class CodeFixAddsNumericLiteralForNonExistingStatusCodeConstantsController : ControllerBase
|
||||||
|
{
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(345)]
|
||||||
|
[ProducesDefaultResponseType]
|
||||||
|
public IActionResult GetItem(int id)
|
||||||
|
{
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
return StatusCode(345);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(new object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers._INPUT_
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
public class CodeFixAddsStatusCodesFromConstructorParametersController : ControllerBase
|
||||||
|
{
|
||||||
|
private const int FieldStatusCode = 201;
|
||||||
|
|
||||||
|
public IActionResult GetItem(int id)
|
||||||
|
{
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
return new StatusCodeResult(422);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 1)
|
||||||
|
{
|
||||||
|
return new StatusCodeResult(StatusCodes.Status202Accepted);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 2)
|
||||||
|
{
|
||||||
|
const int localStatusCode = 204;
|
||||||
|
|
||||||
|
return new StatusCodeResult(localStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 3)
|
||||||
|
{
|
||||||
|
return new StatusCodeResult(FieldStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(new object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers._OUTPUT_
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
public class CodeFixAddsStatusCodesFromConstructorParametersController : ControllerBase
|
||||||
|
{
|
||||||
|
private const int FieldStatusCode = 201;
|
||||||
|
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
|
||||||
|
[ProducesDefaultResponseType]
|
||||||
|
public IActionResult GetItem(int id)
|
||||||
|
{
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
return new StatusCodeResult(422);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 1)
|
||||||
|
{
|
||||||
|
return new StatusCodeResult(StatusCodes.Status202Accepted);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 2)
|
||||||
|
{
|
||||||
|
const int localStatusCode = 204;
|
||||||
|
|
||||||
|
return new StatusCodeResult(localStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 3)
|
||||||
|
{
|
||||||
|
return new StatusCodeResult(FieldStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(new object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers._INPUT_
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
public class CodeFixAddsStatusCodesFromMethodParametersController : ControllerBase
|
||||||
|
{
|
||||||
|
private const int FieldStatusCode = 201;
|
||||||
|
|
||||||
|
public IActionResult GetItem(int id)
|
||||||
|
{
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
return StatusCode(422);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 1)
|
||||||
|
{
|
||||||
|
return StatusCode(StatusCodes.Status202Accepted);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 2)
|
||||||
|
{
|
||||||
|
const int localStatusCode = 204;
|
||||||
|
|
||||||
|
return StatusCode(localStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 3)
|
||||||
|
{
|
||||||
|
return StatusCode(FieldStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(new object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers._OUTPUT_
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
public class CodeFixAddsStatusCodesFromMethodParametersController : ControllerBase
|
||||||
|
{
|
||||||
|
private const int FieldStatusCode = 201;
|
||||||
|
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
|
||||||
|
[ProducesDefaultResponseType]
|
||||||
|
public IActionResult GetItem(int id)
|
||||||
|
{
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
return StatusCode(422);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 1)
|
||||||
|
{
|
||||||
|
return StatusCode(StatusCodes.Status202Accepted);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 2)
|
||||||
|
{
|
||||||
|
const int localStatusCode = 204;
|
||||||
|
|
||||||
|
return StatusCode(localStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 3)
|
||||||
|
{
|
||||||
|
return StatusCode(FieldStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(new object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers._INPUT_
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
public class CodeFixAddsStatusCodesFromObjectInitializerController : ControllerBase
|
||||||
|
{
|
||||||
|
private const int FieldStatusCode = 201;
|
||||||
|
|
||||||
|
public IActionResult GetItem(int id)
|
||||||
|
{
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
return new ObjectResult(new object())
|
||||||
|
{
|
||||||
|
StatusCode = 422
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 1)
|
||||||
|
{
|
||||||
|
return new ObjectResult(new object())
|
||||||
|
{
|
||||||
|
StatusCode = StatusCodes.Status202Accepted
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 2)
|
||||||
|
{
|
||||||
|
const int localStatusCode = 204;
|
||||||
|
|
||||||
|
return new ObjectResult(new object())
|
||||||
|
{
|
||||||
|
StatusCode = localStatusCode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 3)
|
||||||
|
{
|
||||||
|
return new ObjectResult(new object())
|
||||||
|
{
|
||||||
|
ContentTypes = { "application/json" },
|
||||||
|
StatusCode = FieldStatusCode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(new object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Api.Analyzers._OUTPUT_
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
public class CodeFixAddsStatusCodesFromObjectInitializerController : ControllerBase
|
||||||
|
{
|
||||||
|
private const int FieldStatusCode = 201;
|
||||||
|
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
|
||||||
|
[ProducesDefaultResponseType]
|
||||||
|
public IActionResult GetItem(int id)
|
||||||
|
{
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
return new ObjectResult(new object())
|
||||||
|
{
|
||||||
|
StatusCode = 422
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 1)
|
||||||
|
{
|
||||||
|
return new ObjectResult(new object())
|
||||||
|
{
|
||||||
|
StatusCode = StatusCodes.Status202Accepted
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 2)
|
||||||
|
{
|
||||||
|
const int localStatusCode = 204;
|
||||||
|
|
||||||
|
return new ObjectResult(new object())
|
||||||
|
{
|
||||||
|
StatusCode = localStatusCode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 3)
|
||||||
|
{
|
||||||
|
return new ObjectResult(new object())
|
||||||
|
{
|
||||||
|
ContentTypes = { "application/json" },
|
||||||
|
StatusCode = FieldStatusCode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(new object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue