138 lines
4.0 KiB
C#
138 lines
4.0 KiB
C#
// 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;
|
|
using System.Diagnostics;
|
|
using Microsoft.CodeAnalysis;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.Analyzers
|
|
{
|
|
internal static class MvcFacts
|
|
{
|
|
public static bool IsController(INamedTypeSymbol type, INamedTypeSymbol controllerAttribute, INamedTypeSymbol nonControllerAttribute)
|
|
{
|
|
Debug.Assert(type != null);
|
|
Debug.Assert(controllerAttribute != null);
|
|
Debug.Assert(nonControllerAttribute != null);
|
|
|
|
if (type.TypeKind != TypeKind.Class)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (type.IsAbstract)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// We only consider public top-level classes as controllers.
|
|
if (type.DeclaredAccessibility != Accessibility.Public)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (type.ContainingType != null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (type.IsGenericType || type.IsUnboundGenericType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (type.HasAttribute(nonControllerAttribute, inherit: true))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!type.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
|
|
!type.HasAttribute(controllerAttribute, inherit: true))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static bool IsControllerAction(IMethodSymbol method, INamedTypeSymbol nonActionAttribute, IMethodSymbol disposableDispose)
|
|
{
|
|
Debug.Assert(method != null);
|
|
Debug.Assert(nonActionAttribute != null);
|
|
|
|
if (method.MethodKind != MethodKind.Ordinary)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (method.HasAttribute(nonActionAttribute, inherit: true))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Overridden methods from Object class, e.g. Equals(Object), GetHashCode(), etc., are not valid.
|
|
if (GetDeclaringType(method).SpecialType == SpecialType.System_Object)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsIDisposableDispose(method, disposableDispose))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (method.IsStatic)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (method.IsAbstract)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (method.IsGenericMethod)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return method.DeclaredAccessibility == Accessibility.Public;
|
|
}
|
|
|
|
private static INamedTypeSymbol GetDeclaringType(IMethodSymbol method)
|
|
{
|
|
while (method.IsOverride)
|
|
{
|
|
method = method.OverriddenMethod;
|
|
}
|
|
|
|
return method.ContainingType;
|
|
}
|
|
|
|
private static bool IsIDisposableDispose(IMethodSymbol method, IMethodSymbol disposableDispose)
|
|
{
|
|
if (method.Name != disposableDispose.Name)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (method.Parameters.Length != disposableDispose.Parameters.Length)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Explicit implementation
|
|
for (var i = 0; i < method.ExplicitInterfaceImplementations.Length; i++)
|
|
{
|
|
if (method.ExplicitInterfaceImplementations[i].ContainingType.SpecialType == SpecialType.System_IDisposable)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
var implementedMethod = method.ContainingType.FindImplementationForInterfaceMember(disposableDispose);
|
|
return implementedMethod == method;
|
|
}
|
|
}
|
|
}
|