Exemple #1
0
        protected override void InitializeWorker(ApiControllerAnalyzerContext analyzerContext)
        {
            analyzerContext.Context.RegisterSymbolAction(context =>
            {
                var method = (IMethodSymbol)context.Symbol;

                if (!analyzerContext.IsApiAction(method))
                {
                    return;
                }

                foreach (var attribute in method.GetAttributes())
                {
                    if (attribute.AttributeClass.IsAssignableFrom(analyzerContext.RouteAttribute))
                    {
                        return;
                    }
                }

                var properties = ImmutableDictionary.Create <string, string>(StringComparer.Ordinal)
                                 .Add(MethodNameKey, method.Name);

                var location = method.Locations.Length > 0 ? method.Locations[0] : Location.None;
                context.ReportDiagnostic(Diagnostic.Create(
                                             SupportedDiagnostic,
                                             location,
                                             properties: properties));
            }, SymbolKind.Method);
        }
Exemple #2
0
        protected override void InitializeWorker(ApiControllerAnalyzerContext analyzerContext)
        {
            analyzerContext.Context.RegisterSyntaxNodeAction(context =>
            {
                var methodSyntax = (MethodDeclarationSyntax)context.Node;
                if (methodSyntax.Body == null)
                {
                    // Ignore expression bodied methods.
                    return;
                }

                var method = context.SemanticModel.GetDeclaredSymbol(methodSyntax, context.CancellationToken);
                if (!analyzerContext.IsApiAction(method))
                {
                    return;
                }

                if (method.ReturnsVoid || method.ReturnType == analyzerContext.SystemThreadingTaskOfT)
                {
                    // Void or Task returning methods. We don't have to check anything here since we're specifically
                    // looking for return BadRequest(..);
                    return;
                }

                // Only look for top level statements that look like "if (!ModelState.IsValid)"
                foreach (var memberAccessSyntax in methodSyntax.Body.DescendantNodes().OfType <MemberAccessExpressionSyntax>())
                {
                    var ancestorIfStatement = memberAccessSyntax.FirstAncestorOrSelf <IfStatementSyntax>();
                    if (ancestorIfStatement == null)
                    {
                        // Node's not in an if statement.
                        continue;
                    }

                    var symbolInfo = context.SemanticModel.GetSymbolInfo(memberAccessSyntax, context.CancellationToken);

                    if (!(symbolInfo.Symbol is IPropertySymbol property) ||
                        (property.ContainingType != analyzerContext.ModelStateDictionary) ||
                        !string.Equals(property.Name, "IsValid", StringComparison.Ordinal) ||
                        !IsFalseExpression(memberAccessSyntax))
                    {
                        continue;
                    }

                    var containingBlock = (SyntaxNode)ancestorIfStatement;
                    if (containingBlock.Parent.Kind() == SyntaxKind.ElseClause)
                    {
                        containingBlock = containingBlock.Parent;
                    }
                    context.ReportDiagnostic(Diagnostic.Create(SupportedDiagnostic, containingBlock.GetLocation()));
                    return;
                }
            }, SyntaxKind.MethodDeclaration);
        }
        public sealed override void Initialize(AnalysisContext context)
        {
            context.RegisterCompilationStartAction(compilationContext =>
            {
                var analyzerContext = new ApiControllerAnalyzerContext(compilationContext);

                // Only do work if ApiControllerAttribute is defined.
                if (analyzerContext.ApiControllerAttribute == null)
                {
                    return;
                }

                InitializeWorker(analyzerContext);
            });
        }
Exemple #4
0
        protected override void InitializeWorker(ApiControllerAnalyzerContext analyzerContext)
        {
            analyzerContext.Context.RegisterSyntaxNodeAction(context =>
            {
                var methodSyntax = (MethodDeclarationSyntax)context.Node;
                if (methodSyntax.Body == null)
                {
                    // Ignore expression bodied methods.
                }

                var method = context.SemanticModel.GetDeclaredSymbol(methodSyntax, context.CancellationToken);
                if (!analyzerContext.IsApiAction(method))
                {
                    return;
                }

                if (method.ReturnsVoid || method.ReturnType.Kind != SymbolKind.NamedType)
                {
                    return;
                }

                var declaredReturnType  = method.ReturnType;
                var namedReturnType     = (INamedTypeSymbol)method.ReturnType;
                var isTaskOActionResult = false;
                if (namedReturnType.ConstructedFrom?.IsAssignableFrom(analyzerContext.SystemThreadingTaskOfT) ?? false)
                {
                    // Unwrap Task<T>.
                    isTaskOActionResult = true;
                    declaredReturnType  = namedReturnType.TypeArguments[0];
                }

                if (!declaredReturnType.IsAssignableFrom(analyzerContext.IActionResult))
                {
                    // Method signature does not look like IActionResult MyAction or SomeAwaitable<IActionResult>.
                    // Nothing to do here.
                    return;
                }

                // Method returns an IActionResult. Determine if the method block returns an ObjectResult
                foreach (var returnStatement in methodSyntax.DescendantNodes().OfType <ReturnStatementSyntax>())
                {
                    var returnType = context.SemanticModel.GetTypeInfo(returnStatement.Expression, context.CancellationToken);
                    if (returnType.Type == null || returnType.Type.Kind == SymbolKind.ErrorType)
                    {
                        continue;
                    }

                    ImmutableDictionary <string, string> properties = null;
                    if (returnType.Type.IsAssignableFrom(analyzerContext.ObjectResult))
                    {
                        // Check if the method signature looks like "return Ok(userModelInstance)". If so, we can infer the type of userModelInstance
                        if (returnStatement.Expression is InvocationExpressionSyntax invocation &&
                            invocation.ArgumentList.Arguments.Count == 1)
                        {
                            var typeInfo          = context.SemanticModel.GetTypeInfo(invocation.ArgumentList.Arguments[0].Expression);
                            var desiredReturnType = analyzerContext.ActionResultOfT.Construct(typeInfo.Type);
                            if (isTaskOActionResult)
                            {
                                desiredReturnType = analyzerContext.SystemThreadingTaskOfT.Construct(desiredReturnType);
                            }

                            var desiredReturnTypeString = desiredReturnType.ToMinimalDisplayString(
                                context.SemanticModel,
                                methodSyntax.ReturnType.SpanStart);

                            properties = ImmutableDictionary.Create <string, string>(StringComparer.Ordinal)
                                         .Add(ReturnTypeKey, desiredReturnTypeString);
                        }

                        context.ReportDiagnostic(Diagnostic.Create(
                                                     SupportedDiagnostic,
                                                     methodSyntax.ReturnType.GetLocation(),
                                                     properties: properties));
                    }
                }
            }, SyntaxKind.MethodDeclaration);
        }
 protected abstract void InitializeWorker(ApiControllerAnalyzerContext analyzerContext);