Exemple #1
0
        public override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.EnableConcurrentExecution();
            analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            analysisContext.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartContext) =>
            {
                WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartContext.Compilation);
                INamedTypeSymbol?mvcControllerSymbol        = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebMvcController);
                INamedTypeSymbol?mvcControllerBaseSymbol    = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebMvcControllerBase);
                INamedTypeSymbol?actionResultSymbol         = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebMvcActionResult);

                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 IAsyncResult-based action methods.
                    if (!(symbolContext.Symbol is IMethodSymbol methodSymbol) ||
                        methodSymbol.MethodKind != MethodKind.Ordinary ||
                        methodSymbol.IsStatic ||
                        !methodSymbol.IsPublic() ||
                        !(methodSymbol.ReturnType.Inherits(actionResultSymbol) ||          // FxCop implementation only looked at ActionResult-derived return types.
                          wellKnownTypeProvider.IsTaskOfType(
                              methodSymbol.ReturnType,
                              (ITypeSymbol typeArgument) => typeArgument.Inherits(actionResultSymbol))) ||
                        (!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);
            }
                );
        }