public async Task ITypeSymbolExtensionsShouldDetectVoidReturnTypeAsDesired()
        {
            string controllerCode = @"

public interface IDto{
}

public class SampleDto:IDto{
}

public class SamplesController : DtoController<SampleDto> {

    [ActionAttribute]
    public void Do(){
    }

    [ActionAttribute]
    public Task Do2(){
    }

    [ActionAttribute]
    public int Do3(){
        return 0;
    }

    [ActionAttribute]
    public async Task<int> Do4(){
        return 0;
    }
}

public class DtoController<TDto>
    where TDto : IDto
{

}

";
            DefaultProjectDtoControllersProvider controllersProvider = new DefaultProjectDtoControllersProvider();

            DtoController controller = (await controllersProvider.GetProjectDtoControllersWithTheirOperations(CreateProjectFromSourceCodes(controllerCode))).Single();

            Assert.IsTrue(controller.Operations.ElementAt(0).ReturnType.IsVoid());
            Assert.IsTrue(controller.Operations.ElementAt(1).ReturnType.IsVoid());
            Assert.IsFalse(controller.Operations.ElementAt(2).ReturnType.IsVoid());
            Assert.IsFalse(controller.Operations.ElementAt(3).ReturnType.IsVoid());
        }
Exemple #2
0
        public virtual async Task <IList <DtoController> > GetProjectDtoControllersWithTheirOperations(Project project, IList <Project>?allSourceProjects = null)
        {
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            IList <DtoController> dtoControllers = new List <DtoController>();

            foreach (Document doc in project.Documents)
            {
                if (!doc.SupportsSemanticModel)
                {
                    continue;
                }

                SemanticModel semanticModel = await doc.GetSemanticModelAsync().ConfigureAwait(false) ?? throw new InvalidOperationException("SemanticModel is null");

                SyntaxNode root = await doc.GetSyntaxRootAsync().ConfigureAwait(false) ?? throw new InvalidOperationException("SyntaxRoot is null");

                List <ClassDeclarationSyntax> dtoControllersClassDecs = new List <ClassDeclarationSyntax>();

                foreach (ClassDeclarationSyntax classDeclarationSyntax in root.DescendantNodes()
                         .OfType <ClassDeclarationSyntax>())
                {
                    if (classDeclarationSyntax.BaseList == null)
                    {
                        continue;
                    }

                    INamedTypeSymbol controllerSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(classDeclarationSyntax);

                    bool isController = controllerSymbol.IsDtoController();

                    if (isController == true)
                    {
                        dtoControllersClassDecs.Add(classDeclarationSyntax);
                    }
                }

                if (!dtoControllersClassDecs.Any())
                {
                    continue;
                }

                foreach (ClassDeclarationSyntax dtoControllerClassDec in dtoControllersClassDecs)
                {
                    INamedTypeSymbol controllerSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(dtoControllerClassDec);

                    DtoController dtoController = new DtoController
                    {
                        ControllerSymbol = controllerSymbol,
                        Name             = controllerSymbol.Name.Replace("Controller", string.Empty, StringComparison.InvariantCultureIgnoreCase),
                        Operations       = new List <ODataOperation>(),
                        ModelSymbol      = controllerSymbol.BaseType.TypeArguments.ExtendedSingleOrDefault($"Looking for model of ${controllerSymbol.Name}", t => t.IsDto()) ?? await BuildAutoDto(controllerSymbol).ConfigureAwait(false)
                    };

                    if (dtoController.ModelSymbol is ITypeParameterSymbol symbol)
                    {
                        dtoController.ModelSymbol = symbol.ConstraintTypes.ExtendedSingleOrDefault($"Looking for model on generic model {symbol.Name}", t => t.IsDto());
                    }

                    if (dtoController.ControllerSymbol.IsGenericType || dtoController.ControllerSymbol.IsAbstract)
                    {
                        continue;
                    }

                    dtoControllers.Add(dtoController);

                    foreach (MethodDeclarationSyntax methodDecSyntax in dtoControllerClassDec.DescendantNodes().OfType <MethodDeclarationSyntax>())
                    {
                        IMethodSymbol methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(methodDecSyntax);

                        if (!methodSymbol.IsOperation(out AttributeData operationAttribute))
                        {
                            continue;
                        }

                        ODataOperation operation = new ODataOperation
                        {
                            Method     = methodSymbol,
                            Kind       = operationAttribute.AttributeClass.Name == "ActionAttribute" ? ODataOperationKind.Action : ODataOperationKind.Function,
                            ReturnType = methodSymbol.ReturnType
                        };

                        if (operation.Kind == ODataOperationKind.Function)
                        {
                            operation.Parameters = operation.Method.Parameters
                                                   .Where(p => p.Type.Name != "CancellationToken" && p.Type.Name != "ODataQueryOptions")
                                                   .Select(parameter => new ODataOperationParameter
                            {
                                Name = parameter.Name,
                                Type = parameter.Type
                            }).ToList();
                        }
                        else if (operation.Kind == ODataOperationKind.Action && operation.Method.Parameters.Any())
                        {
                            IParameterSymbol actionParameterContainer = operation.Method.Parameters
                                                                        .Where(p => p.Type.Name != "CancellationToken" && p.Type.Name != "ODataQueryOptions")
                                                                        .ExtendedSingleOrDefault($"Finding parameter of {operation.Method.ContainingType.Name}.{operation.Method.Name}. It's expected to see 0 or 1 parameter only.");

                            if (actionParameterContainer != null)
                            {
                                if (actionParameterContainer.Type.IsDto() || actionParameterContainer.Type.IsComplexType() || actionParameterContainer.Type.IsCollectionType())
                                {
                                    operation.Parameters = new List <ODataOperationParameter>
                                    {
                                        new ODataOperationParameter
                                        {
                                            Name = actionParameterContainer.Name,
                                            Type = actionParameterContainer.Type
                                        }
                                    };
                                }
                                // ToDo: else if (parameter is string or primitive or enum or date time or date time offset) { throw an exception; }
                                else
                                {
                                    operation.Parameters = actionParameterContainer.Type.GetMembers()
                                                           .OfType <IPropertySymbol>()
                                                           .Select(prop => new ODataOperationParameter
                                    {
                                        Name = prop.Name,
                                        Type = prop.Type
                                    }).ToList();
                                }
                            }
                        }

                        dtoController.Operations.Add(operation);
                    }
                }
            }

            return(dtoControllers);
        }
Exemple #3
0
        public virtual IList <DtoController> GetProjectDtoControllersWithTheirOperations(Project project)
        {
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            IList <DtoController> dtoControllers = new List <DtoController>();

            foreach (Document doc in project.Documents)
            {
                if (!doc.SupportsSemanticModel)
                {
                    continue;
                }

                SemanticModel semanticModel = doc.GetSemanticModelAsync().Result;

                SyntaxNode root = doc.GetSyntaxRootAsync(CancellationToken.None).Result;

                List <ClassDeclarationSyntax> dtoControllersClassDecs = new List <ClassDeclarationSyntax>();

                foreach (ClassDeclarationSyntax classDeclarationSyntax in root.DescendantNodes()
                         .OfType <ClassDeclarationSyntax>())
                {
                    if (classDeclarationSyntax.BaseList == null)
                    {
                        continue;
                    }

                    INamedTypeSymbol controllerSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(classDeclarationSyntax);

                    INamedTypeSymbol type = controllerSymbol;

                    bool isController = false;

                    while (type != null)
                    {
                        isController = type.BaseType?.Name == "DtoController";

                        if (isController == true)
                        {
                            break;
                        }

                        type = type.BaseType;
                    }

                    if (isController == true)
                    {
                        dtoControllersClassDecs.Add(classDeclarationSyntax);
                    }
                }

                if (!dtoControllersClassDecs.Any())
                {
                    continue;
                }

                foreach (ClassDeclarationSyntax dtoControllerClassDec in dtoControllersClassDecs)
                {
                    INamedTypeSymbol controllerSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(dtoControllerClassDec);

                    DtoController dtoController = new DtoController
                    {
                        ControllerSymbol = controllerSymbol,
                        Name             = controllerSymbol.Name.Replace("Controller", string.Empty),
                        Operations       = new List <ODataOperation>(),
                        ModelSymbol      = controllerSymbol.BaseType.TypeArguments.SingleOrDefault(t => t.IsDto())
                    };

                    if (dtoController.ModelSymbol != null && dtoController.ModelSymbol is ITypeParameterSymbol)
                    {
                        dtoController.ModelSymbol = ((ITypeParameterSymbol)dtoController.ModelSymbol).ConstraintTypes.SingleOrDefault(t => t.IsDto());
                    }

                    if (dtoController.ModelSymbol == null)
                    {
                        continue;
                    }

                    dtoControllers.Add(dtoController);

                    if (dtoController.ControllerSymbol.IsGenericType)
                    {
                        continue;
                    }

                    foreach (MethodDeclarationSyntax methodDecSyntax in dtoControllerClassDec.DescendantNodes().OfType <MethodDeclarationSyntax>())
                    {
                        IMethodSymbol methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(methodDecSyntax);

                        ImmutableArray <AttributeData> attrs = methodSymbol.GetAttributes();

                        AttributeData actionAttribute = attrs.SingleOrDefault(att => att.AttributeClass.Name == "ActionAttribute");

                        AttributeData functionAttribute = attrs.SingleOrDefault(att => att.AttributeClass.Name == "FunctionAttribute");

                        if (actionAttribute == null && functionAttribute == null)
                        {
                            continue;
                        }

                        ODataOperation operation = new ODataOperation
                        {
                            Method     = methodSymbol,
                            Kind       = actionAttribute != null ? ODataOperationKind.Action : ODataOperationKind.Function,
                            ReturnType = methodSymbol.ReturnType
                        };

                        operation.Parameters = operation.Method.GetAttributes()
                                               .Where(att => att.AttributeClass.Name == "ParameterAttribute")
                                               .Select(parameterAttribute => new ODataOperationParameter
                        {
                            Name       = parameterAttribute.ConstructorArguments[0].Value.ToString(),
                            Type       = ((ITypeSymbol)parameterAttribute.ConstructorArguments[1].Value),
                            IsOptional = parameterAttribute.ConstructorArguments.Count() == 3 && object.Equals(parameterAttribute.ConstructorArguments[2].Value, true)
                        }).ToList();

                        dtoController.Operations.Add(operation);
                    }
                }
            }

            return(dtoControllers);
        }
        public virtual async Task <IList <DtoController> > GetProjectDtoControllersWithTheirOperations(Project project, IList <Project> allSourceProjects = null)
        {
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            IList <DtoController> dtoControllers = new List <DtoController>();

            foreach (Document doc in project.Documents)
            {
                if (!doc.SupportsSemanticModel)
                {
                    continue;
                }

                SemanticModel semanticModel = await doc.GetSemanticModelAsync();

                SyntaxNode root = await doc.GetSyntaxRootAsync();

                List <ClassDeclarationSyntax> dtoControllersClassDecs = new List <ClassDeclarationSyntax>();

                foreach (ClassDeclarationSyntax classDeclarationSyntax in root.DescendantNodes()
                         .OfType <ClassDeclarationSyntax>())
                {
                    if (classDeclarationSyntax.BaseList == null)
                    {
                        continue;
                    }

                    INamedTypeSymbol controllerSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(classDeclarationSyntax);

                    INamedTypeSymbol type = controllerSymbol;

                    bool isController = false;

                    while (type != null)
                    {
                        isController = type.BaseType?.Name == "DtoController";

                        if (isController == true)
                        {
                            break;
                        }

                        type = type.BaseType;
                    }

                    if (isController == true)
                    {
                        dtoControllersClassDecs.Add(classDeclarationSyntax);
                    }
                }

                if (!dtoControllersClassDecs.Any())
                {
                    continue;
                }

                foreach (ClassDeclarationSyntax dtoControllerClassDec in dtoControllersClassDecs)
                {
                    INamedTypeSymbol controllerSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(dtoControllerClassDec);

                    DtoController dtoController = new DtoController
                    {
                        ControllerSymbol = controllerSymbol,
                        Name             = controllerSymbol.Name.Replace("Controller", string.Empty),
                        Operations       = new List <ODataOperation>(),
                        ModelSymbol      = controllerSymbol.BaseType.TypeArguments.ExtendedSingleOrDefault($"Looking for model of ${controllerSymbol.Name}", t => t.IsDto())
                    };

                    if (dtoController.ModelSymbol is ITypeParameterSymbol)
                    {
                        dtoController.ModelSymbol = ((ITypeParameterSymbol)dtoController.ModelSymbol).ConstraintTypes.ExtendedSingleOrDefault($"Looking for model on generic model {dtoController.ModelSymbol.Name}", t => t.IsDto());
                    }

                    if (dtoController.ModelSymbol == null)
                    {
                        continue;
                    }

                    dtoControllers.Add(dtoController);

                    if (dtoController.ControllerSymbol.IsGenericType)
                    {
                        continue;
                    }

                    foreach (MethodDeclarationSyntax methodDecSyntax in dtoControllerClassDec.DescendantNodes().OfType <MethodDeclarationSyntax>())
                    {
                        IMethodSymbol methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(methodDecSyntax);

                        ImmutableArray <AttributeData> attrs = methodSymbol.GetAttributes();

                        AttributeData actionAttribute = attrs.ExtendedSingleOrDefault($"Looking for action attribute on {methodSymbol.Name}", att => att.AttributeClass.Name == "ActionAttribute");

                        AttributeData functionAttribute = attrs.ExtendedSingleOrDefault($"Looking for function attribute on {methodSymbol.Name}", att => att.AttributeClass.Name == "FunctionAttribute");

                        if (actionAttribute == null && functionAttribute == null)
                        {
                            continue;
                        }

                        ODataOperation operation = new ODataOperation
                        {
                            Method     = methodSymbol,
                            Kind       = actionAttribute != null ? ODataOperationKind.Action : ODataOperationKind.Function,
                            ReturnType = methodSymbol.ReturnType
                        };

                        if (operation.Kind == ODataOperationKind.Function)
                        {
                            operation.Parameters = operation.Method.Parameters
                                                   .Where(p => p.Type.Name != "CancellationToken" && p.Type.Name != "ODataQueryOptions")
                                                   .Select(parameter => new ODataOperationParameter
                            {
                                Name = parameter.Name,
                                Type = parameter.Type
                            }).ToList();
                        }
                        else if (operation.Kind == ODataOperationKind.Action && operation.Method.Parameters.Any())
                        {
                            IParameterSymbol actionParameterContainer = operation.Method.Parameters
                                                                        .Where(p => p.Type.Name != "CancellationToken" && p.Type.Name != "ODataQueryOptions")
                                                                        .ExtendedSingleOrDefault($"Looking for one parameter other than cancellation token or odata query options on {operation.Method.Name}");

                            if (actionParameterContainer != null)
                            {
                                operation.Parameters = actionParameterContainer.Type.GetMembers()
                                                       .OfType <IPropertySymbol>()
                                                       .Select(prop => new ODataOperationParameter
                                {
                                    Name = prop.Name,
                                    Type = prop.Type
                                }).ToList();
                            }
                        }

                        dtoController.Operations.Add(operation);
                    }
                }
            }

            return(dtoControllers);
        }