Exemplo n.º 1
0
        public override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.EnableConcurrentExecution();
            analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            analysisContext.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartContext) =>
            {
                INamedTypeSymbol mvcControllerSymbol     = WellKnownTypes.MvcController(compilationStartContext.Compilation);
                INamedTypeSymbol mvcControllerBaseSymbol = WellKnownTypes.MvcControllerBase(compilationStartContext.Compilation);
                INamedTypeSymbol actionResultSymbol      = WellKnownTypes.ActionResult(compilationStartContext.Compilation);

                if ((mvcControllerSymbol == null && mvcControllerBaseSymbol == null) || actionResultSymbol == null)
                {
                    // No MVC controllers that return an ActionResult here.
                    return;
                }

                MvcAttributeSymbols mvcAttributeSymbols = new MvcAttributeSymbols(compilationStartContext.Compilation);

                compilationStartContext.RegisterSymbolAction(
                    (SymbolAnalysisContext symbolContext) =>
                {
                    // TODO enhancements: Consider looking at non-ActionResult-derived return types as well.
                    if (!(symbolContext.Symbol is IMethodSymbol methodSymbol) ||
                        methodSymbol.MethodKind != MethodKind.Ordinary ||
                        methodSymbol.IsStatic ||
                        !methodSymbol.IsPublic() ||
                        !methodSymbol.ReturnType.Inherits(actionResultSymbol) ||          // FxCop implementation only looks at ActionResult-derived return types.
                        (!methodSymbol.ContainingType.Inherits(mvcControllerSymbol) &&
                         !methodSymbol.ContainingType.Inherits(mvcControllerBaseSymbol)))
                    {
                        return;
                    }

                    ImmutableArray <AttributeData> methodAttributes = methodSymbol.GetAttributes();
                    mvcAttributeSymbols.ComputeAttributeInfo(methodAttributes, out var verbs, out var isAntiforgeryTokenDefined, out var isAction);

                    if (!isAction)
                    {
                        return;
                    }

                    if (verbs == MvcHttpVerbs.None)
                    {
                        // no verbs specified
                        if (isAntiforgeryTokenDefined)
                        {
                            // antiforgery token attribute is set, but verbs are not specified
                            symbolContext.ReportDiagnostic(Diagnostic.Create(NoVerbsRule, methodSymbol.Locations[0], methodSymbol.MetadataName));
                        }
                        else
                        {
                            // no verbs, no antiforgery token attribute
                            symbolContext.ReportDiagnostic(Diagnostic.Create(NoVerbsNoTokenRule, methodSymbol.Locations[0], methodSymbol.MetadataName));
                        }
                    }
                    else
                    {
                        // verbs are defined
                        if (isAntiforgeryTokenDefined)
                        {
                            if (verbs.HasFlag(MvcHttpVerbs.Get))
                            {
                                symbolContext.ReportDiagnostic(Diagnostic.Create(GetAndTokenRule, methodSymbol.Locations[0], methodSymbol.MetadataName));

                                if ((verbs & (MvcHttpVerbs.Post | MvcHttpVerbs.Put | MvcHttpVerbs.Delete | MvcHttpVerbs.Patch)) != MvcHttpVerbs.None)
                                {
                                    // both verbs, antiforgery token attribute
                                    symbolContext.ReportDiagnostic(Diagnostic.Create(GetAndOtherAndTokenRule, methodSymbol.Locations[0], methodSymbol.MetadataName));
                                }
                            }
                        }
                        else
                        {
                            if ((verbs & (MvcHttpVerbs.Post | MvcHttpVerbs.Put | MvcHttpVerbs.Delete | MvcHttpVerbs.Patch)) != MvcHttpVerbs.None)
                            {
                                // HttpPost, no antiforgery token attribute
                                symbolContext.ReportDiagnostic(Diagnostic.Create(VerbsAndNoTokenRule, methodSymbol.Locations[0], methodSymbol.MetadataName));
                            }
                        }
                    }
                },
                    SymbolKind.Method);
            }
                );
        }